import { InternalServerErrorException } from '@nestjs/common';
import { type IAiServiceClient } from '../../../../infrastructure/services/ai-service.client';
import { IndustrialValuationHandler } from '../industrial-valuation.handler';
import { IndustrialValuationQuery } from '../industrial-valuation.query';

describe('IndustrialValuationHandler', () => {
  let handler: IndustrialValuationHandler;
  let mockAiClient: { predictIndustrial: ReturnType<typeof vi.fn> };
  let mockLogger: { error: ReturnType<typeof vi.fn> };

  const query = new IndustrialValuationQuery(
    'Bình Dương',
    'south',
    0.85,
    500,
    10,
    25,
    40,
    5,
    'factory',
    5000,
    10,
    3,
    2000,
    0.6,
    4,
    'general_industrial',
    0.7,
    3000,
    8000000,
    0.75,
  );

  const aiResponse = {
    estimated_rent_usd_m2: 5.2,
    confidence: 0.65,
    rent_range_low_usd_m2: 4.16,
    rent_range_high_usd_m2: 6.24,
    annual_rent_usd_m2: 62.4,
    total_monthly_rent_usd: 26000,
    comparables: [
      {
        park_name: 'VSIP I',
        province: 'Bình Dương',
        property_type: 'factory',
        area_m2: 5000,
        rent_usd_m2: 5.2,
        similarity_score: 0.85,
      },
    ],
    drivers: [
      { feature: 'province_baseline', importance: 0.16 },
      { feature: 'property_type', importance: 0.12 },
    ],
    model_version: 'heuristic-v1',
  };

  beforeEach(() => {
    mockAiClient = { predictIndustrial: vi.fn() };
    mockLogger = { error: vi.fn() };
    handler = new IndustrialValuationHandler(
      mockAiClient as unknown as IAiServiceClient,
      mockLogger as any,
    );
  });

  it('calls AI service with correct snake_case parameters', async () => {
    mockAiClient.predictIndustrial.mockResolvedValue(aiResponse);

    await handler.execute(query);

    expect(mockAiClient.predictIndustrial).toHaveBeenCalledWith({
      province: 'Bình Dương',
      region: 'south',
      park_occupancy_rate: 0.85,
      park_area_ha: 500,
      park_age_years: 10,
      distance_to_port_km: 25,
      distance_to_airport_km: 40,
      distance_to_highway_km: 5,
      property_type: 'factory',
      area_m2: 5000,
      ceiling_height_m: 10,
      floor_load_ton_m2: 3,
      power_capacity_kva: 2000,
      building_coverage: 0.6,
      loading_docks: 4,
      zoning: 'general_industrial',
      industry_demand_index: 0.7,
      fdi_province_musd: 3000,
      labor_cost_province_vnd: 8000000,
      logistics_connectivity_score: 0.75,
    });
  });

  it('maps AI response to camelCase DTO', async () => {
    mockAiClient.predictIndustrial.mockResolvedValue(aiResponse);

    const result = await handler.execute(query);

    expect(result.estimatedRentUsdM2).toBe(5.2);
    expect(result.confidence).toBe(0.65);
    expect(result.rentRangeLowUsdM2).toBe(4.16);
    expect(result.rentRangeHighUsdM2).toBe(6.24);
    expect(result.annualRentUsdM2).toBe(62.4);
    expect(result.totalMonthlyRentUsd).toBe(26000);
    expect(result.modelVersion).toBe('heuristic-v1');
  });

  it('maps comparable properties to camelCase', async () => {
    mockAiClient.predictIndustrial.mockResolvedValue(aiResponse);

    const result = await handler.execute(query);

    expect(result.comparables).toHaveLength(1);
    expect(result.comparables[0]).toEqual({
      parkName: 'VSIP I',
      province: 'Bình Dương',
      propertyType: 'factory',
      areaM2: 5000,
      rentUsdM2: 5.2,
      similarityScore: 0.85,
    });
  });

  it('maps drivers array', async () => {
    mockAiClient.predictIndustrial.mockResolvedValue(aiResponse);

    const result = await handler.execute(query);

    expect(result.drivers).toHaveLength(2);
    expect(result.drivers[0]).toEqual({ feature: 'province_baseline', importance: 0.16 });
  });

  it('throws InternalServerErrorException on AI service failure', async () => {
    mockAiClient.predictIndustrial.mockRejectedValue(new Error('AI service down'));

    await expect(handler.execute(query)).rejects.toThrow(InternalServerErrorException);
    expect(mockLogger.error).toHaveBeenCalled();
  });
});
