import { describe, it, expect, beforeEach } from 'vitest';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerCardsCarouselComponent } from './customer-cards-carousel.component';
import { BonusCardInfo } from '@isa/crm/data-access';

describe('CustomerCardsCarouselComponent', () => {
  let component: CustomerCardsCarouselComponent;
  let fixture: ComponentFixture<CustomerCardsCarouselComponent>;

  const mockCards: BonusCardInfo[] = [
    {
      code: 'CARD-1',
      firstName: 'John',
      lastName: 'Doe',
      isActive: true,
      isPrimary: true,
      totalPoints: 1500,
      cardNumber: '1234-5678-9012-3456',
    } as BonusCardInfo,
    {
      code: 'CARD-2',
      firstName: 'John',
      lastName: 'Doe',
      isActive: false,
      isPrimary: false,
      totalPoints: 500,
      cardNumber: '9876-5432-1098-7654',
    } as BonusCardInfo,
    {
      code: 'CARD-3',
      firstName: 'John',
      lastName: 'Doe',
      isActive: true,
      isPrimary: false,
      totalPoints: 800,
      cardNumber: '1111-2222-3333-4444',
    } as BonusCardInfo,
  ];

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [CustomerCardsCarouselComponent],
    });

    fixture = TestBed.createComponent(CustomerCardsCarouselComponent);
    component = fixture.componentInstance;
  });

  it('should create', () => {
    expect(component).toBeDefined();
  });

  describe('Inputs', () => {
    it('should accept cards input', () => {
      fixture.componentRef.setInput('cards', mockCards);
      fixture.detectChanges();

      expect(component.cards()).toEqual(mockCards);
    });
  });

  describe('singleCard computed signal', () => {
    it('should return true when there is exactly one card', () => {
      const singleCard: BonusCardInfo[] = [
        { code: 'CARD-1', isActive: true, isPrimary: true, firstName: 'John', lastName: 'Doe', totalPoints: 100 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', singleCard);
      fixture.detectChanges();

      expect(component.singleCard()).toBe(true);
    });

    it('should return false when there are multiple cards', () => {
      fixture.componentRef.setInput('cards', mockCards);
      fixture.detectChanges();

      expect(component.singleCard()).toBe(false);
    });

    it('should return false when there are no cards', () => {
      fixture.componentRef.setInput('cards', []);
      fixture.detectChanges();

      expect(component.singleCard()).toBe(false);
    });
  });

  describe('sortedCards computed signal', () => {
    it('should sort cards with active cards first', () => {
      fixture.componentRef.setInput('cards', mockCards);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      // First two should be active (CARD-1 and CARD-3)
      expect(sorted[0].isActive).toBe(true);
      expect(sorted[1].isActive).toBe(true);
      // Last one should be blocked (CARD-2)
      expect(sorted[2].isActive).toBe(false);
    });

    it('should place blocked cards at the end', () => {
      fixture.componentRef.setInput('cards', mockCards);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      // Blocked card should be last
      expect(sorted[sorted.length - 1].code).toBe('CARD-2');
      expect(sorted[sorted.length - 1].isActive).toBe(false);
    });

    it('should handle all active cards', () => {
      const allActiveCards: BonusCardInfo[] = [
        { code: 'CARD-1', isActive: true, isPrimary: true, firstName: 'John', lastName: 'Doe', totalPoints: 100 } as BonusCardInfo,
        { code: 'CARD-2', isActive: true, isPrimary: false, firstName: 'John', lastName: 'Doe', totalPoints: 200 } as BonusCardInfo,
        { code: 'CARD-3', isActive: true, isPrimary: false, firstName: 'John', lastName: 'Doe', totalPoints: 300 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', allActiveCards);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      // All should remain active
      expect(sorted.every(card => card.isActive)).toBe(true);
      expect(sorted.length).toBe(3);
    });

    it('should handle all blocked cards', () => {
      const allBlockedCards: BonusCardInfo[] = [
        { code: 'CARD-1', isActive: false, isPrimary: false, firstName: 'John', lastName: 'Doe', totalPoints: 100 } as BonusCardInfo,
        { code: 'CARD-2', isActive: false, isPrimary: false, firstName: 'John', lastName: 'Doe', totalPoints: 200 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', allBlockedCards);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      // All should remain blocked
      expect(sorted.every(card => !card.isActive)).toBe(true);
      expect(sorted.length).toBe(2);
    });

    it('should handle empty cards array', () => {
      fixture.componentRef.setInput('cards', []);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      expect(sorted).toEqual([]);
    });

    it('should handle single card', () => {
      const singleCard: BonusCardInfo[] = [
        { code: 'CARD-1', isActive: true, isPrimary: true, firstName: 'John', lastName: 'Doe', totalPoints: 100 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', singleCard);
      fixture.detectChanges();

      const sorted = component.sortedCards();

      expect(sorted.length).toBe(1);
      expect(sorted[0].code).toBe('CARD-1');
    });

    it('should not mutate original cards array', () => {
      const originalCards = [...mockCards];
      fixture.componentRef.setInput('cards', mockCards);
      fixture.detectChanges();

      component.sortedCards();

      // Original array should remain unchanged
      expect(mockCards).toEqual(originalCards);
    });

    it('should maintain sorting when cards input changes', () => {
      const initialCards: BonusCardInfo[] = [
        { code: 'CARD-1', isActive: false, isPrimary: false, firstName: 'John', lastName: 'Doe', totalPoints: 100 } as BonusCardInfo,
        { code: 'CARD-2', isActive: true, isPrimary: true, firstName: 'John', lastName: 'Doe', totalPoints: 200 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', initialCards);
      fixture.detectChanges();

      let sorted = component.sortedCards();
      expect(sorted[0].code).toBe('CARD-2'); // Active first
      expect(sorted[1].code).toBe('CARD-1'); // Blocked last

      // Update with different cards
      const updatedCards: BonusCardInfo[] = [
        { code: 'CARD-3', isActive: true, isPrimary: false, firstName: 'Jane', lastName: 'Doe', totalPoints: 300 } as BonusCardInfo,
        { code: 'CARD-4', isActive: false, isPrimary: false, firstName: 'Jane', lastName: 'Doe', totalPoints: 400 } as BonusCardInfo,
      ];

      fixture.componentRef.setInput('cards', updatedCards);
      fixture.detectChanges();

      sorted = component.sortedCards();
      expect(sorted[0].code).toBe('CARD-3'); // Active first
      expect(sorted[1].code).toBe('CARD-4'); // Blocked last
    });
  });
});
