import { Injectable } from '@nestjs/common';
import { LoggerService } from '@modules/shared';

export interface AiPredictRequest {
  area: number;
  district: string;
  city: string;
  property_type: string;
  bedrooms?: number;
  bathrooms?: number;
  floors?: number;
  frontage?: number;
  road_width?: number;
  year_built?: number | null;
  has_legal_paper?: boolean;
}

export interface AiPredictResponse {
  estimated_price_vnd: number;
  confidence: number;
  price_per_m2: number;
  price_range_low: number;
  price_range_high: number;
}

/**
 * AVM v2 request — extended feature set for residential ensemble.
 * Matches `AVMv2PredictRequest` in libs/ai-services/app/models/avm_v2.py.
 */
export interface AiPredictV2Request {
  district: string;
  city: string;
  property_type: string;
  area_m2: number;
  distance_to_cbd_km?: number;
  distance_to_metro_km?: number;
  distance_to_school_km?: number;
  distance_to_hospital_km?: number;
  distance_to_park_km?: number;
  distance_to_mall_km?: number;
  flood_zone_risk?: number;
  neighborhood_score?: number;
  rooms?: number;
  floor_level?: number;
  total_floors?: number;
  direction?: string;
  floor_ratio?: number;
  building_age_years?: number;
  has_elevator?: boolean;
  has_parking?: boolean;
  has_pool?: boolean;
  has_legal_paper?: boolean;
  developer_reputation?: number;
  avg_price_district_3m_vnd_m2?: number;
  listing_density?: number;
  absorption_rate?: number;
  dom_avg?: number;
  price_momentum_30d?: number;
  yoy_change?: number;
  renovation_score?: number;
  view_quality?: number;
  interior_quality?: number;
  noise_level?: number;
  natural_light?: number;
  month?: number;
  quarter?: number;
  is_year_end?: boolean;
}

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

export interface AiPredictV2Comparable {
  district: string;
  property_type: string;
  area_m2: number;
  price_vnd: number;
  price_per_m2_vnd: number;
  similarity_score: number;
}

export interface AiPredictV2Response {
  estimated_price_vnd: number;
  confidence: number;
  price_per_m2_vnd: number;
  price_range_low_vnd: number;
  price_range_high_vnd: number;
  drivers?: AiPredictV2FeatureImportance[];
  comparables?: AiPredictV2Comparable[];
  model_version?: string;
  ensemble_method?: string;
}

export interface AiIndustrialPredictRequest {
  province: string;
  region: string;
  park_occupancy_rate: number;
  park_area_ha: number;
  park_age_years: number;
  distance_to_port_km: number;
  distance_to_airport_km: number;
  distance_to_highway_km: number;
  property_type: string;
  area_m2: number;
  ceiling_height_m?: number;
  floor_load_ton_m2?: number;
  power_capacity_kva?: number;
  building_coverage?: number;
  loading_docks?: number;
  zoning?: string;
  industry_demand_index?: number;
  fdi_province_musd?: number;
  labor_cost_province_vnd?: number;
  logistics_connectivity_score?: number;
}

export interface AiIndustrialComparable {
  park_name: string;
  province: string;
  property_type: string;
  area_m2: number;
  rent_usd_m2: number;
  similarity_score: number;
}

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

export interface AiIndustrialPredictResponse {
  estimated_rent_usd_m2: number;
  confidence: number;
  rent_range_low_usd_m2: number;
  rent_range_high_usd_m2: number;
  annual_rent_usd_m2: number;
  total_monthly_rent_usd: number;
  comparables: AiIndustrialComparable[];
  drivers: AiIndustrialFeatureImportance[];
  model_version: string;
}

export interface AiModerationRequest {
  text: string;
  context?: string;
}

export interface AiModerationFlag {
  category: string;
  severity: string;
  matched_text: string;
  reason: string;
}

export interface AiModerationResponse {
  is_flagged: boolean;
  score: number;
  flags: AiModerationFlag[];
  cleaned_text: string | null;
}

export interface AiNeighborhoodPOICounts {
  education: number;
  healthcare: number;
  transport: number;
  shopping: number;
  greenery: number;
  safety: number;
}

export interface AiNeighborhoodScoreRequest {
  district: string;
  city: string;
  poi_counts: AiNeighborhoodPOICounts;
}

export interface AiNeighborhoodScoreResponse {
  district: string;
  city: string;
  education_score: number;
  healthcare_score: number;
  transport_score: number;
  shopping_score: number;
  greenery_score: number;
  safety_score: number;
  total_score: number;
  poi_counts: Record<string, number>;
  algorithm_version: string;
}

export const AI_SERVICE_CLIENT = Symbol('AI_SERVICE_CLIENT');

export interface IAiServiceClient {
  predict(req: AiPredictRequest): Promise<AiPredictResponse>;
  predictV2(req: AiPredictV2Request): Promise<AiPredictV2Response>;
  predictIndustrial(req: AiIndustrialPredictRequest): Promise<AiIndustrialPredictResponse>;
  moderate(req: AiModerationRequest): Promise<AiModerationResponse>;
  scoreNeighborhood(req: AiNeighborhoodScoreRequest): Promise<AiNeighborhoodScoreResponse>;
  isAvailable(): Promise<boolean>;
}

@Injectable()
export class AiServiceClient implements IAiServiceClient {
  private readonly baseUrl: string;
  private readonly apiKey: string;
  private readonly timeoutMs: number;

  constructor(private readonly logger: LoggerService) {
    this.baseUrl = process.env['AI_SERVICE_URL'] ?? 'http://localhost:8000';
    this.apiKey = process.env['AI_SERVICE_API_KEY'] ?? '';
    this.timeoutMs = Number(process.env['AI_SERVICE_TIMEOUT_MS']) || 5000;
  }

  async predict(req: AiPredictRequest): Promise<AiPredictResponse> {
    return this.post<AiPredictResponse>('/avm/predict', req);
  }

  async predictV2(req: AiPredictV2Request): Promise<AiPredictV2Response> {
    return this.post<AiPredictV2Response>('/avm/v2/predict', req);
  }

  async predictIndustrial(req: AiIndustrialPredictRequest): Promise<AiIndustrialPredictResponse> {
    return this.post<AiIndustrialPredictResponse>('/avm/industrial/predict', req);
  }

  async moderate(req: AiModerationRequest): Promise<AiModerationResponse> {
    return this.post<AiModerationResponse>('/moderation/check', req);
  }

  async scoreNeighborhood(
    req: AiNeighborhoodScoreRequest,
  ): Promise<AiNeighborhoodScoreResponse> {
    return this.post<AiNeighborhoodScoreResponse>('/neighborhood/score', req);
  }

  async isAvailable(): Promise<boolean> {
    try {
      const response = await fetch(`${this.baseUrl}/health`, {
        method: 'GET',
        signal: AbortSignal.timeout(2000),
      });
      return response.ok;
    } catch {
      return false;
    }
  }

  private async post<T>(path: string, body: unknown): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    };
    if (this.apiKey) {
      headers['X-API-Key'] = this.apiKey;
    }

    const response = await fetch(url, {
      method: 'POST',
      headers,
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(this.timeoutMs),
    });

    if (!response.ok) {
      const text = await response.text().catch(() => '');
      throw new Error(`AI service ${path} returned ${response.status}: ${text}`);
    }

    return response.json() as Promise<T>;
  }
}
