import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, signal } from '@angular/core';
import { CarouselComponent } from './carousel.component';

// Test host component with mock items
@Component({
  selector: 'ui-test-host',
  template: `
    <ui-carousel
      [gap]="gap()"
      [arrowAutoHide]="arrowAutoHide()"
    >
      @for (item of items(); track item) {
        <div class="test-item" [style.width.px]="300">{{ item }}</div>
      }
    </ui-carousel>
  `,
  imports: [CarouselComponent],
})
class TestHostComponent {
  items = signal(['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']);
  gap = signal('1rem');
  arrowAutoHide = signal(true);
}

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

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [CarouselComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(CarouselComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

  it('should have default input values', () => {
    expect(component.gap()).toBe('1rem');
    expect(component.arrowAutoHide()).toBe(true);
    expect(component.disabled()).toBe(false);
  });

  it('should apply auto-hide class when arrowAutoHide is true', () => {
    fixture.componentRef.setInput('arrowAutoHide', true);
    fixture.detectChanges();

    const hostElement = fixture.nativeElement as HTMLElement;
    expect(hostElement.classList.contains('ui-carousel--auto-hide')).toBe(true);
  });

  it('should not apply auto-hide class when arrowAutoHide is false', () => {
    fixture.componentRef.setInput('arrowAutoHide', false);
    fixture.detectChanges();

    const hostElement = fixture.nativeElement as HTMLElement;
    expect(hostElement.classList.contains('ui-carousel--auto-hide')).toBe(false);
  });

  it('should have tabindex 0 for keyboard navigation', () => {
    const hostElement = fixture.nativeElement as HTMLElement;
    expect(hostElement.getAttribute('tabindex')).toBe('0');
  });
});

describe('CarouselComponent with content', () => {
  let hostComponent: TestHostComponent;
  let fixture: ComponentFixture<TestHostComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [TestHostComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(TestHostComponent);
    hostComponent = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should render projected content', () => {
    const items = fixture.nativeElement.querySelectorAll('.test-item');
    expect(items.length).toBe(5);
    expect(items[0].textContent.trim()).toBe('Item 1');
  });

  it('should apply gap style to scroll container', () => {
    hostComponent.gap.set('2rem');
    fixture.detectChanges();

    const container = fixture.nativeElement.querySelector('.ui-carousel__container');
    expect(container.style.gap).toBe('2rem');
  });

  it('should show navigation buttons with proper data attributes', () => {
    const buttons = fixture.nativeElement.querySelectorAll('.ui-carousel__button');

    if (buttons.length > 0) {
      const leftButton = fixture.nativeElement.querySelector('[data-which="carousel-previous"]');
      const rightButton = fixture.nativeElement.querySelector('[data-which="carousel-next"]');

      if (leftButton) {
        expect(leftButton.getAttribute('data-what')).toBe('button');
        expect(leftButton.getAttribute('aria-label')).toBe('Previous');
      }

      if (rightButton) {
        expect(rightButton.getAttribute('data-what')).toBe('button');
        expect(rightButton.getAttribute('aria-label')).toBe('Next');
      }
    }
  });

  it('should use ui-icon-button directive for navigation buttons', () => {
    const buttons = fixture.nativeElement.querySelectorAll('.ui-carousel__button');

    if (buttons.length > 0) {
      buttons.forEach((button: Element) => {
        expect(button.hasAttribute('uiiconbutton')).toBe(true);
      });
    }
  });

  it('should have scroll container with proper classes', () => {
    const container = fixture.nativeElement.querySelector('.ui-carousel__container');
    expect(container).toBeTruthy();
    expect(container.classList.contains('ui-carousel__container')).toBe(true);
  });

  it('should change arrowAutoHide input', () => {
    hostComponent.arrowAutoHide.set(false);
    fixture.detectChanges();

    const carousel = fixture.debugElement.children[0].componentInstance as CarouselComponent;
    expect(carousel.arrowAutoHide()).toBe(false);
  });
});

describe('CarouselComponent keyboard navigation', () => {
  let component: CarouselComponent;
  let fixture: ComponentFixture<CarouselComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [CarouselComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(CarouselComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should call navigateToPrevious on ArrowLeft keydown', () => {
    const spy = vi.spyOn(component, 'navigateToPrevious');
    const event = new KeyboardEvent('keydown', { key: 'ArrowLeft' });

    const hostElement = fixture.nativeElement as HTMLElement;
    hostElement.dispatchEvent(event);

    expect(spy).toHaveBeenCalled();
  });

  it('should call navigateToNext on ArrowRight keydown', () => {
    const spy = vi.spyOn(component, 'navigateToNext');
    const event = new KeyboardEvent('keydown', { key: 'ArrowRight' });

    const hostElement = fixture.nativeElement as HTMLElement;
    hostElement.dispatchEvent(event);

    expect(spy).toHaveBeenCalled();
  });
});

describe('CarouselComponent disabled state', () => {
  let component: CarouselComponent;
  let fixture: ComponentFixture<CarouselComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [CarouselComponent],
    }).compileComponents();

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

  it('should hide buttons when disabled', () => {
    fixture.componentRef.setInput('disabled', true);
    fixture.detectChanges();

    const buttons = fixture.nativeElement.querySelectorAll('.ui-carousel__button');
    expect(buttons.length).toBe(0);
  });

  it('should not navigate when disabled and navigateToPrevious is called', () => {
    fixture.componentRef.setInput('disabled', true);
    fixture.detectChanges();

    const initialTranslate = component['currentTranslateX']();
    component.navigateToPrevious();

    expect(component['currentTranslateX']()).toBe(initialTranslate);
  });

  it('should not navigate when disabled and navigateToNext is called', () => {
    fixture.componentRef.setInput('disabled', true);
    fixture.detectChanges();

    const initialTranslate = component['currentTranslateX']();
    component.navigateToNext();

    expect(component['currentTranslateX']()).toBe(initialTranslate);
  });

  it('should not navigate when disabled and navigateToStart is called', () => {
    fixture.componentRef.setInput('disabled', false);
    fixture.detectChanges();

    // Set a non-zero position first
    component['currentTranslateX'].set(-100);

    fixture.componentRef.setInput('disabled', true);
    fixture.detectChanges();

    component.navigateToStart();

    expect(component['currentTranslateX']()).toBe(-100);
  });
});
