import { Inject, InternalServerErrorException } from '@nestjs/common';
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { DomainException, LoggerService } from '@modules/shared';
import {
  AI_SERVICE_CLIENT,
  type IAiServiceClient,
  type AiIndustrialPredictResponse,
} from '../../../infrastructure/services/ai-service.client';
import { IndustrialValuationQuery } from './industrial-valuation.query';

export interface IndustrialValuationComparable {
  parkName: string;
  province: string;
  propertyType: string;
  areaM2: number;
  rentUsdM2: number;
  similarityScore: number;
}

export interface IndustrialValuationDriver {
  feature: string;
  importance: number;
}

export interface IndustrialValuationDto {
  estimatedRentUsdM2: number;
  confidence: number;
  rentRangeLowUsdM2: number;
  rentRangeHighUsdM2: number;
  annualRentUsdM2: number;
  totalMonthlyRentUsd: number;
  comparables: IndustrialValuationComparable[];
  drivers: IndustrialValuationDriver[];
  modelVersion: string;
}

function mapResponse(res: AiIndustrialPredictResponse): IndustrialValuationDto {
  return {
    estimatedRentUsdM2: res.estimated_rent_usd_m2,
    confidence: res.confidence,
    rentRangeLowUsdM2: res.rent_range_low_usd_m2,
    rentRangeHighUsdM2: res.rent_range_high_usd_m2,
    annualRentUsdM2: res.annual_rent_usd_m2,
    totalMonthlyRentUsd: res.total_monthly_rent_usd,
    comparables: res.comparables.map((c) => ({
      parkName: c.park_name,
      province: c.province,
      propertyType: c.property_type,
      areaM2: c.area_m2,
      rentUsdM2: c.rent_usd_m2,
      similarityScore: c.similarity_score,
    })),
    drivers: res.drivers.map((d) => ({
      feature: d.feature,
      importance: d.importance,
    })),
    modelVersion: res.model_version,
  };
}

@QueryHandler(IndustrialValuationQuery)
export class IndustrialValuationHandler implements IQueryHandler<IndustrialValuationQuery> {
  constructor(
    @Inject(AI_SERVICE_CLIENT) private readonly aiClient: IAiServiceClient,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: IndustrialValuationQuery): Promise<IndustrialValuationDto> {
    try {
      const response = await this.aiClient.predictIndustrial({
        province: query.province,
        region: query.region,
        park_occupancy_rate: query.parkOccupancyRate,
        park_area_ha: query.parkAreaHa,
        park_age_years: query.parkAgeYears,
        distance_to_port_km: query.distanceToPortKm,
        distance_to_airport_km: query.distanceToAirportKm,
        distance_to_highway_km: query.distanceToHighwayKm,
        property_type: query.propertyType,
        area_m2: query.areaM2,
        ceiling_height_m: query.ceilingHeightM,
        floor_load_ton_m2: query.floorLoadTonM2,
        power_capacity_kva: query.powerCapacityKva,
        building_coverage: query.buildingCoverage,
        loading_docks: query.loadingDocks,
        zoning: query.zoning,
        industry_demand_index: query.industryDemandIndex,
        fdi_province_musd: query.fdiProvinceMusd,
        labor_cost_province_vnd: query.laborCostProvinceVnd,
        logistics_connectivity_score: query.logisticsConnectivityScore,
      });

      return mapResponse(response);
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to estimate industrial rent: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException(
        'Không thể ước tính giá thuê khu công nghiệp. Vui lòng thử lại sau.',
      );
    }
  }
}
