import { Component, signal, ViewChild } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { StepperComponent } from './stepper.component';
import { StepComponent } from './step.component';

@Component({
  imports: [StepperComponent, StepComponent],
  template: `
    <app-stepper #stepper>
      <app-step label="Step 1" [isValid]="step1Valid()">
        <div id="content-1">Content 1</div>
      </app-step>
      <app-step label="Step 2" [isValid]="step2Valid()">
        <div id="content-2">Content 2</div>
      </app-step>
    </app-stepper>
  `
})
class TestHostComponent {
  @ViewChild('stepper') stepper!: StepperComponent;
  step1Valid = signal(true);
  step2Valid = signal(true);
}

describe('StepperComponent & StepComponent', () => {
  async function setup() {
    await TestBed.configureTestingModule({
      imports: [TestHostComponent, StepperComponent, StepComponent]
    }).compileComponents();

    const fixture = TestBed.createComponent(TestHostComponent);
    fixture.detectChanges();
    return { fixture, component: fixture.componentInstance };
  }

  it('renders step labels in the indicator bar', async () => {
    const { fixture } = await setup();
    const labels = fixture.nativeElement.querySelectorAll('.stepper-header__label');
    expect(labels.length).toBe(2);
    expect(labels[0].textContent.trim()).toBe('Step 1');
    expect(labels[1].textContent.trim()).toBe('Step 2');
  });

  it('activates the first step by default and shows its content', async () => {
    const { fixture } = await setup();
    const content1 = fixture.nativeElement.querySelector('#content-1');
    const content2 = fixture.nativeElement.querySelector('#content-2');

    expect(content1).not.toBeNull();
    expect(content2).toBeNull();
  });

  it('advances to step 2 when next() is called and current step is valid', async () => {
    const { fixture, component } = await setup();

    component.stepper.next();
    fixture.detectChanges();

    const content1 = fixture.nativeElement.querySelector('#content-1');
    const content2 = fixture.nativeElement.querySelector('#content-2');

    expect(content1).toBeNull();
    expect(content2).not.toBeNull();
    expect(component.stepper.currentStepIndex()).toBe(1);
  });

  it('does not advance to step 2 when next() is called if current step is invalid', async () => {
    const { fixture, component } = await setup();
    component.step1Valid.set(false);
    fixture.detectChanges();

    component.stepper.next();
    fixture.detectChanges();

    const content1 = fixture.nativeElement.querySelector('#content-1');
    const content2 = fixture.nativeElement.querySelector('#content-2');

    expect(content1).not.toBeNull();
    expect(content2).toBeNull();
    expect(component.stepper.currentStepIndex()).toBe(0);
  });

  it('goes back to step 1 when previous() is called', async () => {
    const { fixture, component } = await setup();

    component.stepper.next();
    fixture.detectChanges();
    expect(component.stepper.currentStepIndex()).toBe(1);

    component.stepper.previous();
    fixture.detectChanges();

    expect(component.stepper.currentStepIndex()).toBe(0);
    expect(fixture.nativeElement.querySelector('#content-1')).not.toBeNull();
  });

  it('marks the first circle as active by default', async () => {
    const { fixture } = await setup();
    const items = fixture.nativeElement.querySelectorAll('.stepper-header__item');
    expect(items[0].classList.contains('is-active')).toBe(true);
    expect(items[1].classList.contains('is-active')).toBe(false);
  });

  it('marks step 1 as completed and step 2 as active after advancing', async () => {
    const { fixture, component } = await setup();

    component.stepper.next();
    fixture.detectChanges();

    const items = fixture.nativeElement.querySelectorAll('.stepper-header__item');
    expect(items[0].classList.contains('is-completed')).toBe(true);
    expect(items[1].classList.contains('is-active')).toBe(true);
  });

  it('allows navigating back to a completed step via goToStep()', async () => {
    const { fixture, component } = await setup();

    component.stepper.next();
    fixture.detectChanges();
    expect(component.stepper.currentStepIndex()).toBe(1);

    component.stepper.goToStep(0);
    fixture.detectChanges();

    expect(component.stepper.currentStepIndex()).toBe(0);
    expect(fixture.nativeElement.querySelector('#content-1')).not.toBeNull();
  });
});
