import { TestBed, getTestBed } from '@angular/core/testing';
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';

import { ProductVerticalWithCartCardComponent } from './product-vertical-with-cart-card.component';

describe('ProductVerticalWithCartCardComponent', () => {
  beforeAll(() => {
    try {
      getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
    } catch {
      // Test environment may already be initialized by another setup entrypoint.
    }
  });

  afterEach(() => {
    TestBed.resetTestingModule();
  });

  async function createComponent(description = 'Pancho con aderezo a elecciÃ³n.') {
    await TestBed.configureTestingModule({
      imports: [ProductVerticalWithCartCardComponent],
    }).compileComponents();

    const fixture = TestBed.createComponent(ProductVerticalWithCartCardComponent);
    fixture.componentRef.setInput('title', 'Pancho');
    fixture.componentRef.setInput('description', description);
    fixture.componentRef.setInput('price', 11500);
    fixture.detectChanges();

    return fixture;
  }

  it('renders the product information and formats the price', async () => {
    const fixture = await createComponent();
    const element = fixture.nativeElement as HTMLElement;

    expect(element.querySelector('.product-vertical-with-cart-card__title')?.textContent).toContain(
      'Pancho',
    );
    expect(
      element.querySelector('.product-vertical-with-cart-card__description')?.textContent,
    ).toContain('Pancho con aderezo a elecciÃ³n.');
    expect(
      element.querySelector('.product-vertical-with-cart-card__price')?.textContent?.trim(),
    ).toBe('$ 11.500');
  });

  it('does not render an empty description', async () => {
    const fixture = await createComponent('');

    expect(
      (fixture.nativeElement as HTMLElement).querySelector(
        '.product-vertical-with-cart-card__description',
      ),
    ).toBeNull();
  });

  it('shows the backend availability message with the reusable tooltip', async () => {
    const fixture = await createComponent();
    fixture.componentRef.setInput('maximumAddableQuantity', 0);
    fixture.componentRef.setInput(
      'unavailableMessage',
      'Alcanzaste el cupo máximo permitido para este producto.',
    );
    fixture.detectChanges();

    const tooltip = (fixture.nativeElement as HTMLElement).querySelector('app-tooltip');

    expect(tooltip?.querySelector('i.fa-solid.fa-circle-info')).not.toBeNull();
    expect(tooltip?.textContent).toContain(
      'Alcanzaste el cupo máximo permitido para este producto.',
    );
  });

  it('updates the quantity with the reusable quantity selector', async () => {
    const fixture = await createComponent();
    const buttons = fixture.nativeElement.querySelectorAll(
      'app-quantity-selector button',
    ) as NodeListOf<HTMLButtonElement>;

    expect(fixture.componentInstance.quantity()).toBe(1);

    buttons[1].click();
    fixture.detectChanges();
    expect(fixture.componentInstance.quantity()).toBe(2);

    buttons[0].click();
    fixture.detectChanges();
    expect(fixture.componentInstance.quantity()).toBe(1);
  });

  it('emits buy when Comprar is clicked', async () => {
    const fixture = await createComponent();
    const buySpy = vi.fn();
    fixture.componentInstance.buy.subscribe(buySpy);

    const button = fixture.nativeElement.querySelector(
      '.product-vertical-with-cart-card__actions .btn-primary',
    ) as HTMLButtonElement;
    button.click();

    expect(buySpy).toHaveBeenCalledWith({ quantity: 1, variant: null });
  });

  it('emits addToCart with the current quantity', async () => {
    const fixture = await createComponent();
    const addToCartSpy = vi.fn();
    fixture.componentInstance.addToCart.subscribe(addToCartSpy);
    fixture.componentInstance.quantity.set(3);
    fixture.detectChanges();

    const button = fixture.nativeElement.querySelector(
      '.product-vertical-with-cart-card__actions .btn-outline-primary',
    ) as HTMLButtonElement;
    button.click();

    expect(addToCartSpy).toHaveBeenCalledWith({ quantity: 3, variant: null });
  });

  it('uses the shared primary and secondary buttons', async () => {
    const fixture = await createComponent();
    const element = fixture.nativeElement as HTMLElement;

    expect(
      element.querySelectorAll('.product-vertical-with-cart-card__actions app-button'),
    ).toHaveLength(2);
    expect(
      element.querySelector('.product-vertical-with-cart-card__actions .btn-primary'),
    ).not.toBeNull();
    expect(
      element.querySelector('.product-vertical-with-cart-card__actions .btn-outline-primary'),
    ).not.toBeNull();
  });

  it('places price and quantity together above a single variant selector', async () => {
    const fixture = await createComponent();
    fixture.componentRef.setInput('variants', [
      { id: 10, values: { fecha: '10 de octubre' } },
      { id: 11, values: { fecha: '11 de octubre' } },
    ]);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    const summary = element.querySelector('.product-vertical-with-cart-card__summary');
    const selectors = element.querySelector('.product-vertical-with-cart-card__variant-selectors');

    expect(summary?.querySelector('.product-vertical-with-cart-card__price')).not.toBeNull();
    expect(summary?.querySelector('app-quantity-selector')).not.toBeNull();
    expect(selectors?.querySelectorAll('.variant-selector__select')).toHaveLength(1);
    expect(selectors?.querySelector('app-quantity-selector')).toBeNull();
  });

  it('places all variant selectors together below price and quantity', async () => {
    const fixture = await createComponent();
    fixture.componentRef.setInput('variants', [
      { id: 20, values: { fecha: '10 de octubre', turno: 'MaÃƒÂ±ana' } },
      { id: 21, values: { fecha: '10 de octubre', turno: 'Tarde' } },
    ]);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    const layout = element.querySelector('.product-vertical-with-cart-card__variants');

    expect(layout?.querySelector('.product-vertical-with-cart-card__summary')).not.toBeNull();
    expect(
      layout?.querySelectorAll(
        '.product-vertical-with-cart-card__variant-selectors .variant-selector__select',
      ),
    ).toHaveLength(2);
  });

  it('emits the selected variant with the purchase action', async () => {
    const fixture = await createComponent();
    fixture.componentRef.setInput('variants', [
      { id: 30, values: { fecha: '10 de octubre' } },
      { id: 31, values: { fecha: '11 de octubre' } },
    ]);
    fixture.detectChanges();
    const buySpy = vi.fn();
    fixture.componentInstance.buy.subscribe(buySpy);

    const select = fixture.nativeElement.querySelector(
      '.variant-selector__select',
    ) as HTMLSelectElement;
    select.value = select.options[1].value;
    select.dispatchEvent(new Event('change'));
    fixture.detectChanges();

    const button = fixture.nativeElement.querySelector(
      '.product-vertical-with-cart-card__actions .btn-primary',
    ) as HTMLButtonElement;
    button.click();

    expect(buySpy).toHaveBeenCalledWith({ quantity: 1, variant: 31 });
  });

  it('prioritizes the selected variant description and price', async () => {
    const fixture = await createComponent('DescripciÃ³n general');
    fixture.componentRef.setInput('variants', [
      {
        id: 40,
        descripcion: 'Almuerzo en comedor',
        precio: '10000.00',
        values: { servicio: 'Comedor' },
      },
      {
        id: 41,
        descripcion: 'Almuerzo en vianda',
        precio: '8000.00',
        values: { servicio: 'Vianda' },
      },
    ]);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    expect(
      element.querySelector('.product-vertical-with-cart-card__description')?.textContent,
    ).toContain('Almuerzo en comedor');
    expect(
      element.querySelector('.product-vertical-with-cart-card__price')?.textContent?.trim(),
    ).toBe('$ 10.000');

    const select = element.querySelector('.variant-selector__select') as HTMLSelectElement;
    select.value = select.options[1].value;
    select.dispatchEvent(new Event('change'));
    fixture.detectChanges();

    expect(
      element.querySelector('.product-vertical-with-cart-card__description')?.textContent,
    ).toContain('Almuerzo en vianda');
    expect(
      element.querySelector('.product-vertical-with-cart-card__price')?.textContent?.trim(),
    ).toBe('$ 8.000');
  });
});
