import { TestBed } from '@angular/core/testing';
import { convertToParamMap } from '@angular/router';
import { firstValueFrom, Observable, of, throwError } from 'rxjs';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { CatalogItemDetail } from '../../../../core/services/catalog/catalog.interface';
import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import {
  PRODUCT_DETAIL_ERROR_MESSAGE,
  PRODUCT_DETAIL_INVALID_ID_MESSAGE,
  ProductDetailResolvedData,
  productDetailResolver,
} from './product-detail-page.resolver';

describe('productDetailResolver', () => {
  const product: CatalogItemDetail = {
    id: 1,
    type: 'product',
    category_id: 10,
    brand_id: null,
    slug: 'auriculares-bluetooth',
    nombre: 'Auriculares Bluetooth',
    descripcion: 'Auriculares bluetooth de prueba',
    precio: '24999',
    category: 'Tecnologia',
    brand: null,
    images: [],
    inventory_policy: 'tracked',
    has_tickets: false,
    minimum_use_date: null,
    maximum_use_date: null,
    maximum_addable_quantity: 0,
    attributes: [],
    variants: [],
  };

  let catalogServiceStub: { getCatalogItem: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    catalogServiceStub = {
      getCatalogItem: vi.fn().mockReturnValue(of(product)),
    };

    TestBed.configureTestingModule({
      providers: [
        {
          provide: CatalogService,
          useValue: catalogServiceStub,
        },
      ],
    });
  });

  it('resolves the product detail for the route id', async () => {
    const result = TestBed.runInInjectionContext(() =>
      productDetailResolver(createRouteSnapshot('1'), {} as never),
    );

    await expect(firstValueFrom(result as Observable<ProductDetailResolvedData>)).resolves.toEqual({
      product,
      error: null,
    });
    expect(catalogServiceStub.getCatalogItem).toHaveBeenCalledWith(1);
  });

  it('returns an error state for invalid ids', async () => {
    const result = TestBed.runInInjectionContext(() =>
      productDetailResolver(createRouteSnapshot('abc'), {} as never),
    );

    await expect(firstValueFrom(result as Observable<ProductDetailResolvedData>)).resolves.toEqual({
      product: null,
      error: PRODUCT_DETAIL_INVALID_ID_MESSAGE,
    });
    expect(catalogServiceStub.getCatalogItem).not.toHaveBeenCalled();
  });

  it('returns an error state when the request fails', async () => {
    catalogServiceStub.getCatalogItem.mockReturnValue(throwError(() => new Error('boom')));

    const result = TestBed.runInInjectionContext(() =>
      productDetailResolver(createRouteSnapshot('1'), {} as never),
    );

    await expect(firstValueFrom(result as Observable<ProductDetailResolvedData>)).resolves.toEqual({
      product: null,
      error: PRODUCT_DETAIL_ERROR_MESSAGE,
    });
  });
});

function createRouteSnapshot(id: string) {
  return {
    paramMap: convertToParamMap({ id }),
  } as never;
}
