import { PrismaPriceValidator } from '../../infrastructure/services/prisma-price-validator';

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

  beforeEach(() => {
    mockPrisma = { $queryRaw: vi.fn() };
    const mockLogger = { log: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), verbose: vi.fn() };
    validator = new PrismaPriceValidator(mockPrisma as any, mockLogger as any);
  });

  it('returns valid + not suspicious for normal price within market range', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([{ min_price: 30_000_000, max_price: 100_000_000 }]);

    const result = await validator.validate({
      priceVND: 5_000_000_000n,
      areaM2: 80,
      propertyType: 'APARTMENT',
      district: 'Quận 1',
    });

    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(false);
    expect(result.pricePerM2).toBe(62_500_000);
  });

  it('flags suspicious low price', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([{ min_price: 50_000_000, max_price: 100_000_000 }]);

    const result = await validator.validate({
      priceVND: 1_000_000_000n,
      areaM2: 80,
      propertyType: 'APARTMENT',
      district: 'Quận 1',
    });

    // 12.5M per m2, min threshold is 50M * 0.5 = 25M → 12.5M < 25M → suspicious
    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(true);
    expect(result.reason).toContain('thấp hơn');
  });

  it('flags suspicious high price', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([{ min_price: 30_000_000, max_price: 80_000_000 }]);

    const result = await validator.validate({
      priceVND: 20_000_000_000n,
      areaM2: 80,
      propertyType: 'APARTMENT',
      district: 'Quận 1',
    });

    // 250M per m2, max threshold is 80M * 1.5 = 120M → 250M > 120M → suspicious
    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(true);
    expect(result.reason).toContain('cao hơn');
  });

  it('returns invalid for zero area', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    const result = await validator.validate({
      priceVND: 5_000_000_000n,
      areaM2: 0,
      propertyType: 'APARTMENT',
      district: 'Quận 1',
    });

    expect(result.isValid).toBe(false);
    expect(result.isSuspicious).toBe(true);
    expect(result.reason).toContain('không hợp lệ');
  });

  it('uses default ranges when no market data available', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    const result = await validator.validate({
      priceVND: 5_000_000_000n,
      areaM2: 80,
      propertyType: 'APARTMENT',
      district: 'Quận 9',
    });

    expect(result.isValid).toBe(true);
    // 62.5M per m2, default APARTMENT range is 15M-200M → within range
    expect(result.isSuspicious).toBe(false);
    expect(result.minPricePerM2).toBe(15_000_000);
    expect(result.maxPricePerM2).toBe(200_000_000);
  });

  it('handles database error gracefully using defaults', async () => {
    mockPrisma.$queryRaw.mockRejectedValue(new Error('DB connection failed'));

    const result = await validator.validate({
      priceVND: 5_000_000_000n,
      areaM2: 80,
      propertyType: 'TOWNHOUSE',
      district: 'Quận 1',
    });

    expect(result.isValid).toBe(true);
    expect(result.minPricePerM2).toBe(20_000_000);
    expect(result.maxPricePerM2).toBe(500_000_000);
  });
});
