import type { IAiServiceClient } from '../services/ai-service.client';
import { HttpAVMService } from '../services/http-avm.service';
import type { PrismaAVMService } from '../services/prisma-avm.service';

describe('HttpAVMService', () => {
  let service: HttpAVMService;
  let mockAiClient: IAiServiceClient;
  let mockFallback: PrismaAVMService;
  let mockPrisma: { property: { findUnique: ReturnType<typeof vi.fn> } };

  beforeEach(() => {
    mockAiClient = {
      predict: vi.fn(),
      moderate: vi.fn(),
      isAvailable: vi.fn(),
    };

    mockFallback = {
      estimateValue: vi.fn(),
      getComparables: vi.fn().mockResolvedValue([]),
    } as unknown as PrismaAVMService;

    mockPrisma = {
      property: { findUnique: vi.fn() },
    };

    const mockLogger = { log: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), verbose: vi.fn() };

    service = new HttpAVMService(
      mockAiClient,
      mockFallback,
      mockPrisma as never,
      mockLogger as any,
    );
  });

  describe('estimateValue', () => {
    it('uses AI service when available', async () => {
      mockPrisma.property.findUnique.mockResolvedValue({
        areaM2: 80,
        district: 'Quận 1',
        city: 'Hồ Chí Minh',
        propertyType: 'APARTMENT',
        bedrooms: 2,
        bathrooms: 2,
        floors: null,
        yearBuilt: 2020,
        legalStatus: 'SO_DO',
      });

      (mockAiClient.predict as ReturnType<typeof vi.fn>).mockResolvedValue({
        estimated_price_vnd: 5_000_000_000,
        confidence: 0.82,
        price_per_m2: 62_500_000,
        price_range_low: 4_250_000_000,
        price_range_high: 5_750_000_000,
      });

      const result = await service.estimateValue({ propertyId: 'prop-1' });

      expect(result.estimatedPrice).toBe('5000000000');
      expect(result.confidence).toBe(0.82);
      expect(result.modelVersion).toBe('ai-service-v1.0');
      expect(mockFallback.estimateValue).not.toHaveBeenCalled();
    });

    it('falls back to PrismaAVM when AI service fails', async () => {
      (mockAiClient.predict as ReturnType<typeof vi.fn>).mockRejectedValue(
        new Error('ECONNREFUSED'),
      );

      mockPrisma.property.findUnique.mockResolvedValue({
        areaM2: 80,
        district: 'Quận 1',
        city: 'Hồ Chí Minh',
        propertyType: 'APARTMENT',
        bedrooms: 2,
        bathrooms: 2,
        floors: null,
        yearBuilt: 2020,
        legalStatus: 'SO_DO',
      });

      const fallbackResult = {
        estimatedPrice: '4800000000',
        confidence: 0.6,
        pricePerM2: 60_000_000,
        comparables: [],
        modelVersion: 'avm-v1.0',
      };
      (mockFallback.estimateValue as ReturnType<typeof vi.fn>).mockResolvedValue(fallbackResult);

      const result = await service.estimateValue({ propertyId: 'prop-1' });

      expect(result).toEqual(fallbackResult);
      expect(mockFallback.estimateValue).toHaveBeenCalledWith({ propertyId: 'prop-1' });
    });

    it('uses coordinates directly when no propertyId', async () => {
      (mockAiClient.predict as ReturnType<typeof vi.fn>).mockResolvedValue({
        estimated_price_vnd: 4_000_000_000,
        confidence: 0.65,
        price_per_m2: 50_000_000,
        price_range_low: 3_000_000_000,
        price_range_high: 5_000_000_000,
      });

      const result = await service.estimateValue({
        latitude: 10.762,
        longitude: 106.66,
        areaM2: 80,
        propertyType: 'APARTMENT',
      });

      expect(result.estimatedPrice).toBe('4000000000');
      expect(mockPrisma.property.findUnique).not.toHaveBeenCalled();
    });
  });

  describe('getComparables', () => {
    it('delegates to fallback PrismaAVM service', async () => {
      const comparables = [{ propertyId: 'p1', distanceMeters: 100 }];
      (mockFallback.getComparables as ReturnType<typeof vi.fn>).mockResolvedValue(comparables);

      const result = await service.getComparables('prop-1', 2000);

      expect(result).toEqual(comparables);
      expect(mockFallback.getComparables).toHaveBeenCalledWith('prop-1', 2000);
    });
  });
});
