import { Inject } from '@nestjs/common';
import { type IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { PrismaService } from '@modules/shared';
import { EstimateIndustrialRentQuery } from './estimate-industrial-rent.query';

interface RentEstimateResult {
  estimated_rent_usd_m2: number;
  pricing_unit: string;
  total_monthly_usd: number;
  total_lease_usd: number;
  management_fee_usd_m2: number | null;
  deposit_months: number;
  market_comparison: {
    province_low: number | null;
    province_high: number | null;
    province_avg: number | null;
  };
  breakdown: { item: string; amount: number }[];
}

@QueryHandler(EstimateIndustrialRentQuery)
export class EstimateIndustrialRentHandler
  implements IQueryHandler<EstimateIndustrialRentQuery, RentEstimateResult>
{
  constructor(@Inject(PrismaService) private readonly prisma: PrismaService) {}

  async execute(query: EstimateIndustrialRentQuery): Promise<RentEstimateResult> {
    const { province, propertyType, areaM2, leaseDurationYears, parkName, requiresCrane, requiredPowerKva, requiresWastewater } = query;

    // Get market data for the province
    const provinceParks = await this.prisma.industrialPark.findMany({
      where: { province: { contains: province, mode: 'insensitive' } },
      select: {
        name: true,
        landRentUsdM2Year: true,
        rbfRentUsdM2Month: true,
        rbwRentUsdM2Month: true,
        managementFeeUsd: true,
        occupancyRate: true,
      },
    });

    // If specific park requested, try to find it
    let specificPark = parkName
      ? provinceParks.find((p) => p.name.toLowerCase().includes(parkName.toLowerCase()))
      : null;

    // Calculate base rent based on property type
    const rentField = this.getRentField(propertyType);
    const rents = provinceParks
      .map((p) => {
        const val = p[rentField];
        return val != null ? Number(val) : null;
      })
      .filter((r): r is number => r != null);

    const provinceLow = rents.length > 0 ? Math.min(...rents) : null;
    const provinceHigh = rents.length > 0 ? Math.max(...rents) : null;
    const provinceAvg = rents.length > 0 ? rents.reduce((a, b) => a + b, 0) / rents.length : null;

    // Determine base rent
    let baseRentUsdM2: number;
    if (specificPark && specificPark[rentField] != null) {
      baseRentUsdM2 = Number(specificPark[rentField]);
    } else if (provinceAvg != null) {
      baseRentUsdM2 = provinceAvg;
    } else {
      // Fallback to national averages by property type
      baseRentUsdM2 = this.getNationalAvgRent(propertyType);
    }

    // Apply adjustments
    const breakdown: { item: string; amount: number }[] = [];
    let adjustedRent = baseRentUsdM2;

    breakdown.push({ item: `Base ${this.getPropertyTypeLabel(propertyType)} rent`, amount: baseRentUsdM2 });

    // Crane surcharge
    if (requiresCrane) {
      const craneSurcharge = baseRentUsdM2 * 0.08;
      adjustedRent += craneSurcharge;
      breakdown.push({ item: 'Overhead crane surcharge (+8%)', amount: craneSurcharge });
    }

    // High power requirement surcharge
    if (requiredPowerKva && requiredPowerKva > 500) {
      const powerSurcharge = baseRentUsdM2 * 0.05;
      adjustedRent += powerSurcharge;
      breakdown.push({ item: 'High power capacity surcharge (+5%)', amount: powerSurcharge });
    }

    // Wastewater treatment surcharge
    if (requiresWastewater) {
      const wastewaterSurcharge = baseRentUsdM2 * 0.03;
      adjustedRent += wastewaterSurcharge;
      breakdown.push({ item: 'Wastewater treatment surcharge (+3%)', amount: wastewaterSurcharge });
    }

    // Long lease discount
    if (leaseDurationYears >= 20) {
      const discount = adjustedRent * 0.10;
      adjustedRent -= discount;
      breakdown.push({ item: 'Long-term lease discount (≥20yr, -10%)', amount: -discount });
    } else if (leaseDurationYears >= 10) {
      const discount = adjustedRent * 0.05;
      adjustedRent -= discount;
      breakdown.push({ item: 'Long-term lease discount (≥10yr, -5%)', amount: -discount });
    }

    // Large area discount
    if (areaM2 >= 10_000) {
      const discount = adjustedRent * 0.07;
      adjustedRent -= discount;
      breakdown.push({ item: 'Large area discount (≥10,000m², -7%)', amount: -discount });
    } else if (areaM2 >= 5_000) {
      const discount = adjustedRent * 0.03;
      adjustedRent -= discount;
      breakdown.push({ item: 'Large area discount (≥5,000m², -3%)', amount: -discount });
    }

    adjustedRent = Math.round(adjustedRent * 100) / 100;

    // Determine pricing unit and compute totals
    const isMonthlyType = propertyType !== 'industrial_land';
    const pricingUnit = isMonthlyType ? 'USD/m²/month' : 'USD/m²/year';
    const totalMonthlyUsd = isMonthlyType
      ? Math.round(adjustedRent * areaM2 * 100) / 100
      : Math.round((adjustedRent * areaM2 / 12) * 100) / 100;
    const totalLeaseUsd = Math.round(totalMonthlyUsd * 12 * leaseDurationYears * 100) / 100;

    // Management fee
    const managementFeeUsdM2 = specificPark?.managementFeeUsd != null
      ? Number(specificPark.managementFeeUsd)
      : (provinceParks.length > 0
        ? provinceParks.reduce((sum, p) => sum + (p.managementFeeUsd != null ? Number(p.managementFeeUsd) : 0), 0) / provinceParks.length || null
        : null);

    return {
      estimated_rent_usd_m2: adjustedRent,
      pricing_unit: pricingUnit,
      total_monthly_usd: totalMonthlyUsd,
      total_lease_usd: totalLeaseUsd,
      management_fee_usd_m2: managementFeeUsdM2 ? Math.round(managementFeeUsdM2 * 100) / 100 : null,
      deposit_months: leaseDurationYears >= 10 ? 6 : 3,
      market_comparison: {
        province_low: provinceLow ? Math.round(provinceLow * 100) / 100 : null,
        province_high: provinceHigh ? Math.round(provinceHigh * 100) / 100 : null,
        province_avg: provinceAvg ? Math.round(provinceAvg * 100) / 100 : null,
      },
      breakdown: breakdown.map((b) => ({ item: b.item, amount: Math.round(b.amount * 100) / 100 })),
    };
  }

  private getRentField(propertyType: string): 'landRentUsdM2Year' | 'rbfRentUsdM2Month' | 'rbwRentUsdM2Month' {
    switch (propertyType) {
      case 'ready_built_factory':
        return 'rbfRentUsdM2Month';
      case 'ready_built_warehouse':
      case 'logistics_center':
        return 'rbwRentUsdM2Month';
      default:
        return 'landRentUsdM2Year';
    }
  }

  private getPropertyTypeLabel(propertyType: string): string {
    const labels: Record<string, string> = {
      industrial_land: 'Industrial land',
      ready_built_factory: 'Ready-built factory',
      ready_built_warehouse: 'Ready-built warehouse',
      logistics_center: 'Logistics center',
      office_in_park: 'Office in park',
      data_center: 'Data center',
    };
    return labels[propertyType] ?? propertyType;
  }

  private getNationalAvgRent(propertyType: string): number {
    // Vietnamese national average industrial rents (2024-2025 market data)
    const averages: Record<string, number> = {
      industrial_land: 120,        // USD/m²/year
      ready_built_factory: 5.5,    // USD/m²/month
      ready_built_warehouse: 4.8,  // USD/m²/month
      logistics_center: 5.0,       // USD/m²/month
      office_in_park: 8.0,         // USD/m²/month
      data_center: 12.0,           // USD/m²/month
    };
    return averages[propertyType] ?? 5.0;
  }
}
