import { signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ActivatedRoute, convertToParamMap, provideRouter } from '@angular/router';
import { of } from 'rxjs';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { CartService } from '../../../../core/services/cart/cart.service';
import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import { CatalogAvailabilityService } from '../../../../core/services/catalog/catalog-availability.service';
import { Tenant } from '../../../../core/services/tenant.interface';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import { ProductListComponent } from '../../../../shared/components/product-list/product-list.component';
import { SearchPageComponent } from './search-page.component';

describe('SearchPageComponent', () => {
  const searchCatalog = vi.fn();
  const tenant = signal({
    search_product_layout: 'row',
    search_group_layout: 'simple_vertical',
    search_items_per_page: 8,
  } as Tenant);

  beforeEach(async () => {
    searchCatalog.mockReset();
    searchCatalog.mockReturnValue(
      of({
        data: [
          {
            id: 1,
            nombre: 'Running',
            descripcion: 'Zapatillas',
            precio: '100.00',
            variants: [],
          },
        ],
        links: {
          first: '/catalog-items?page=1',
          last: '/catalog-items?page=2',
          prev: null,
          next: '/catalog-items?page=2',
        },
        meta: {
          current_page: 1,
          from: 1,
          last_page: 2,
          links: [],
          path: '/catalog-items',
          per_page: 8,
          to: 1,
          total: 10,
        },
      }),
    );

    await TestBed.configureTestingModule({
      imports: [SearchPageComponent],
      providers: [
        provideRouter([]),
        {
          provide: ActivatedRoute,
          useValue: {
            queryParamMap: of(convertToParamMap({ q: 'running', page: '1' })),
          },
        },
        {
          provide: CatalogService,
          useValue: {
            searchCatalog,
          },
        },
        {
          provide: TenantService,
          useValue: { tenant: tenant.asReadonly() },
        },
        {
          provide: CartService,
          useValue: { addItem: vi.fn() },
        },
        {
          provide: ToastService,
          useValue: {
            success: vi.fn(),
            danger: vi.fn(),
          },
        },
      ],
    }).compileComponents();
  });

  it('searches from the URL and applies the tenant presentation configuration', () => {
    const fixture = TestBed.createComponent(SearchPageComponent);
    fixture.detectChanges();

    expect(searchCatalog).toHaveBeenCalledWith({
      q: 'running',
      page: 1,
    });

    const productList = fixture.debugElement.query(By.directive(ProductListComponent))
      .componentInstance as ProductListComponent;

    expect(productList.layout()).toBe('row');
    expect(productList.groupLayout()).toBe('simple_vertical');
    expect(Array.isArray(productList.items())).toBe(true);
    expect((fixture.nativeElement as HTMLElement).textContent).toContain(
      'Se muestran 1 de 10 resultados.',
    );
  });

  it('repeats the current search when catalog availability changes', () => {
    const fixture = TestBed.createComponent(SearchPageComponent);
    fixture.detectChanges();

    TestBed.inject(CatalogAvailabilityService).notifyAvailabilityChanged();

    expect(searchCatalog).toHaveBeenCalledTimes(2);
    expect(searchCatalog).toHaveBeenLastCalledWith({ q: 'running', page: 1 });
  });

  it('renders the search title and query subtitle with the category header layout', () => {
    const fixture = TestBed.createComponent(SearchPageComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    const header = element.querySelector('.search-results__header');
    const title = element.querySelector('#search-results-title');
    const subtitle = element.querySelector('.search-results__subtitle');

    expect(header?.classList).toContain('mb-5');
    expect(title?.classList).toContain('search-results__title');
    expect(title?.classList).toContain('mb-0');
    expect(subtitle?.textContent).toContain('Resultados para');
    expect(subtitle?.textContent).toContain('running');
  });

  it('does not search when the query has fewer than three characters', () => {
    TestBed.overrideProvider(ActivatedRoute, {
      useValue: {
        queryParamMap: of(convertToParamMap({ q: 'ab', page: '1' })),
      },
    });

    const fixture = TestBed.createComponent(SearchPageComponent);
    fixture.detectChanges();

    expect(searchCatalog).not.toHaveBeenCalled();
    expect((fixture.nativeElement as HTMLElement).textContent).toContain(
      'Ingresá al menos 3 caracteres para buscar.',
    );
  });
});
