import { ReindexAllCommand } from '../../application/commands/reindex-all/reindex-all.command';
import { GeoSearchQuery } from '../../application/queries/geo-search/geo-search.query';
import { SearchPropertiesQuery } from '../../application/queries/search-properties/search-properties.query';
import { SearchController } from '../controllers/search.controller';

describe('SearchController', () => {
  let controller: SearchController;
  let mockCommandBus: { execute: ReturnType<typeof vi.fn> };
  let mockQueryBus: { execute: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockCommandBus = { execute: vi.fn() };
    mockQueryBus = { execute: vi.fn() };
    controller = new SearchController(mockCommandBus as any, mockQueryBus as any);
  });

  it('search executes SearchPropertiesQuery with correct params', async () => {
    const mockResult = { hits: [], totalFound: 0, page: 1, perPage: 20, totalPages: 0, searchTimeMs: 1 };
    mockQueryBus.execute.mockResolvedValue(mockResult);

    const dto = {
      q: 'căn hộ Quận 7',
      propertyType: 'APARTMENT',
      transactionType: 'SALE',
      priceMin: 1000000000,
      priceMax: 5000000000,
      areaMin: 50,
      areaMax: 200,
      bedrooms: 2,
      district: 'Quận 7',
      city: 'Hồ Chí Minh',
      sortBy: 'price_asc',
      page: 1,
      perPage: 20,
    };

    const result = await controller.search(dto as any);

    expect(mockQueryBus.execute).toHaveBeenCalledWith(
      new SearchPropertiesQuery(
        dto.q,
        dto.propertyType,
        dto.transactionType,
        dto.priceMin,
        dto.priceMax,
        dto.areaMin,
        dto.areaMax,
        dto.bedrooms,
        dto.district,
        dto.city,
        dto.sortBy,
        dto.page,
        dto.perPage,
      ),
    );
    expect(result).toBe(mockResult);
  });

  it('geoSearch executes GeoSearchQuery with correct params', async () => {
    const mockResult = { hits: [], totalFound: 0, page: 1, perPage: 20, totalPages: 0, searchTimeMs: 2 };
    mockQueryBus.execute.mockResolvedValue(mockResult);

    const dto = {
      lat: 10.776,
      lng: 106.700,
      radiusKm: 5,
      propertyType: 'HOUSE',
      transactionType: 'RENT',
      priceMin: 5000000,
      priceMax: 20000000,
      sortBy: 'distance',
      page: 1,
      perPage: 10,
    };

    const result = await controller.geoSearch(dto as any);

    expect(mockQueryBus.execute).toHaveBeenCalledWith(
      new GeoSearchQuery(
        dto.lat,
        dto.lng,
        dto.radiusKm,
        dto.propertyType,
        dto.transactionType,
        dto.priceMin,
        dto.priceMax,
        dto.sortBy,
        dto.page,
        dto.perPage,
      ),
    );
    expect(result).toBe(mockResult);
  });

  it('reindex executes ReindexAllCommand', async () => {
    const mockResult = { indexed: 42, total: 42 };
    mockCommandBus.execute.mockResolvedValue(mockResult);

    const result = await controller.reindex();

    expect(mockCommandBus.execute).toHaveBeenCalledWith(new ReindexAllCommand());
    expect(result).toBe(mockResult);
  });
});
