import { describe, it, expect, vi, beforeEach } from 'vitest';
import { PrismaPriceValidator } from '../services/prisma-price-validator';

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

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

  it('should return valid for normal price within default range', async () => {
    // No market data — falls back to defaults
    mockPrisma.$queryRaw.mockResolvedValue([]);

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

    // 5B / 80 = 62.5M per m2; APARTMENT default range: 15M-200M
    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(false);
    expect(result.pricePerM2).toBe(62_500_000);
  });

  it('should return 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('should flag suspiciously low price', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    // 100M / 100 = 1M per m2 — way below APARTMENT min of 15M * 0.5 = 7.5M
    const result = await validator.validate({
      priceVND: 100_000_000n,
      areaM2: 100,
      propertyType: 'APARTMENT',
      district: 'Quận 7',
    });

    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(true);
    expect(result.reason).toContain('thấp hơn');
  });

  it('should flag suspiciously high price', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([]);

    // 100B / 100 = 1B per m2 — above APARTMENT max of 200M * 1.5 = 300M
    const result = await validator.validate({
      priceVND: 100_000_000_000n,
      areaM2: 100,
      propertyType: 'APARTMENT',
      district: 'Quận 1',
    });

    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(true);
    expect(result.reason).toContain('cao hơn');
  });

  it('should use market data when available', async () => {
    mockPrisma.$queryRaw.mockResolvedValue([
      { min_price: 50_000_000, max_price: 100_000_000 },
    ]);

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

    // 6B / 80 = 75M per m2; market range: 50M-100M — within range
    expect(result.isValid).toBe(true);
    expect(result.isSuspicious).toBe(false);
    expect(result.minPricePerM2).toBe(50_000_000);
    expect(result.maxPricePerM2).toBe(100_000_000);
  });

  it('should fall back to defaults when market query fails', async () => {
    mockPrisma.$queryRaw.mockRejectedValue(new Error('DB error'));

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

    expect(result.isValid).toBe(true);
    expect(mockLogger.warn).toHaveBeenCalled();
  });
});
