import { describe, it, expect, vi, beforeEach } from 'vitest';
import { PrismaDuplicateDetector } from '../services/prisma-duplicate-detector';

describe('PrismaDuplicateDetector', () => {
  let detector: PrismaDuplicateDetector;
  let mockPrisma: { $queryRaw: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockPrisma = {
      $queryRaw: vi.fn().mockResolvedValue([]),
    };
    detector = new PrismaDuplicateDetector(mockPrisma as any);
  });

  it('returns empty array when no nearby properties found', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    const result = await detector.findDuplicates({
      excludePropertyId: 'prop-new',
      latitude: 10.7769,
      longitude: 106.7009,
      addressNormalized: '123 nguyen hue quan 1',
      agentId: 'agent-1',
      propertyType: 'APARTMENT',
    });

    expect(result).toEqual([]);
    expect(mockPrisma.$queryRaw).toHaveBeenCalledTimes(1);
  });

  it('flags addressMatch + sameAgent on a hard-duplicate row', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([
      {
        listing_id: 'listing-dup',
        property_id: 'prop-dup',
        title: 'Căn hộ đẹp Quận 1',
        address: '123 Nguyễn Huệ',
        address_normalized: '123 nguyen hue phuong ben nghe quan 1 tp ho chi minh',
        district: 'Quận 1',
        property_type: 'APARTMENT',
        distance_meters: 25,
        agent_id: 'agent-1',
      },
    ]);

    const result = await detector.findDuplicates({
      excludePropertyId: 'prop-new',
      latitude: 10.7769,
      longitude: 106.7009,
      addressNormalized: '123 nguyen hue phuong ben nghe quan 1 tp ho chi minh',
      agentId: 'agent-1',
      propertyType: 'APARTMENT',
    });

    expect(result).toHaveLength(1);
    expect(result[0]!.listingId).toBe('listing-dup');
    expect(result[0]!.propertyId).toBe('prop-dup');
    expect(result[0]!.distanceMeters).toBe(25);
    expect(result[0]!.addressMatch).toBe(true);
    expect(result[0]!.sameAgent).toBe(true);
  });

  it('returns nearby candidates with addressMatch=false when normalized address differs', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([
      {
        listing_id: 'listing-near',
        property_id: 'prop-near',
        title: 'Căn hộ khác',
        address: '125 Nguyễn Huệ',
        address_normalized: '125 nguyen hue phuong ben nghe quan 1 tp ho chi minh',
        district: 'Quận 1',
        property_type: 'APARTMENT',
        distance_meters: 40,
        agent_id: 'agent-2',
      },
    ]);

    const result = await detector.findDuplicates({
      excludePropertyId: 'prop-new',
      latitude: 10.7769,
      longitude: 106.7009,
      addressNormalized: '123 nguyen hue phuong ben nghe quan 1 tp ho chi minh',
      agentId: 'agent-1',
      propertyType: 'APARTMENT',
    });

    expect(result).toHaveLength(1);
    expect(result[0]!.addressMatch).toBe(false);
    expect(result[0]!.sameAgent).toBe(false);
  });

  it('treats missing addressNormalized on either side as no addressMatch', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([
      {
        listing_id: 'listing-x',
        property_id: 'prop-x',
        title: 'Cũ — chưa backfill',
        address: '1 Lê Lợi',
        address_normalized: null,
        district: 'Quận 1',
        property_type: 'APARTMENT',
        distance_meters: 10,
        agent_id: 'agent-1',
      },
    ]);

    const result = await detector.findDuplicates({
      excludePropertyId: 'prop-new',
      latitude: 10.7769,
      longitude: 106.7009,
      addressNormalized: '1 le loi quan 1',
      agentId: 'agent-1',
      propertyType: 'APARTMENT',
    });

    expect(result[0]!.addressMatch).toBe(false);
    expect(result[0]!.sameAgent).toBe(true);
  });

  it('accepts a custom radius override', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    await detector.findDuplicates({
      excludePropertyId: 'prop-new',
      latitude: 10.7769,
      longitude: 106.7009,
      addressNormalized: 'whatever',
      propertyType: 'TOWNHOUSE',
      radiusMeters: 200,
    });

    expect(mockPrisma.$queryRaw).toHaveBeenCalledTimes(1);
  });
});
