import { type IListingRepository } from '@modules/listings/domain/repositories/listing.repository';
import { GetSimilarListingsHandler } from '../queries/get-similar-listings/get-similar-listings.handler';
import { GetSimilarListingsQuery } from '../queries/get-similar-listings/get-similar-listings.query';

describe('GetSimilarListingsHandler', () => {
  let handler: GetSimilarListingsHandler;
  let mockListingRepo: { [K in keyof IListingRepository]: ReturnType<typeof vi.fn> };

  const mockSimilar = [
    {
      id: 'listing-2',
      title: 'Căn hộ Q1 tương tự',
      priceVND: '4800000000',
      areaM2: 65,
      district: 'Quận 1',
      thumbnailUrl: 'https://cdn.example.com/img.jpg',
      publishedAt: '2026-04-01T00:00:00.000Z',
    },
    {
      id: 'listing-3',
      title: 'Căn hộ Q1 khác',
      priceVND: '5100000000',
      areaM2: 70,
      district: 'Quận 1',
      thumbnailUrl: null,
      publishedAt: '2026-03-15T00:00:00.000Z',
    },
  ];

  beforeEach(() => {
    mockListingRepo = {
      findById: vi.fn(),
      findByIdWithProperty: vi.fn(),
      findSimilar: vi.fn(),
      save: vi.fn(),
      update: vi.fn(),
      delete: vi.fn(),
      search: vi.fn(),
      findByStatus: vi.fn(),
      findBySellerId: vi.fn(),
    };

    handler = new GetSimilarListingsHandler(mockListingRepo as any);
  });

  it('returns similar listings for a valid id and limit', async () => {
    mockListingRepo.findSimilar.mockResolvedValue(mockSimilar);

    const result = await handler.execute(new GetSimilarListingsQuery('listing-1', 5));

    expect(mockListingRepo.findSimilar).toHaveBeenCalledWith('listing-1', 5);
    expect(result).toHaveLength(2);
    expect(result[0].id).toBe('listing-2');
    expect(result[1].district).toBe('Quận 1');
  });

  it('returns empty array when listing has no similar results', async () => {
    mockListingRepo.findSimilar.mockResolvedValue([]);

    const result = await handler.execute(new GetSimilarListingsQuery('listing-unknown', 5));

    expect(result).toEqual([]);
  });

  it('passes limit correctly to repository', async () => {
    mockListingRepo.findSimilar.mockResolvedValue(mockSimilar.slice(0, 1));

    await handler.execute(new GetSimilarListingsQuery('listing-1', 1));

    expect(mockListingRepo.findSimilar).toHaveBeenCalledWith('listing-1', 1);
  });
});
