import type { Geometry } from "geojson";

export interface ParcelAnalysisNoiseSource {
  source_type: "highway" | "railway" | "industrial" | "aerodrome";
  road_class: string | null;
  name: string | null;
  distance_m: number;
  estimated_db: number;
}

export interface ParcelAnalysisNoise {
  score: number;
  estimated_db: number;
  level: "тихо" | "умеренный" | "шумно";
  sources: ParcelAnalysisNoiseSource[];
}

export interface ParcelAnalysisAirQuality {
  pm2_5: number;
  pm10: number;
  no2: number;
  ts: string;
  source: string;
}

export interface ParcelAnalysisWind {
  dominant_direction_deg: number;
  dominant_direction_label: string;
  max_speed_m_s: number | null;
  forecast_days: number;
  source: string;
}

export interface ParcelAnalysisCompetitor {
  obj_id: number;
  comm_name: string | null;
  dev_name: string | null;
  obj_class: string | null;
  flat_count: number | null;
  district_name: string | null;
  distance_m: number;
  // Added manually — backend PR #276 (site_status in /analyze).
  // Codegen will overwrite after backend deploy (additive, backward compat).
  site_status?: string | null; // 'Строящиеся' | 'Сданные' | null
  ready_dt?: string | null; // ISO date
}

export interface ParcelAnalysisDistrict {
  district_name: string;
  median_price_per_m2: number;
  dist_to_center: number;
}

export interface ParcelAnalysisPoi {
  name: string | null;
  distance_m: number;
  last_edit: string | null;
  lat: number;
  lon: number;
}

export interface ParcelAnalysisWeather {
  forecast_days: number;
  temperature: {
    min_c: number | null;
    max_c: number | null;
    avg_max_c: number | null;
    avg_min_c: number | null;
  };
  precipitation_total_mm: number;
  precipitation_days: number;
  uv_index_max: number | null;
  wind: ParcelAnalysisWind;
  source: string;
  note: string;
}

export interface ParcelAnalysisGeology {
  data_available: boolean;
  note: string;
  links: {
    karpinsky_webgis: string;
    efgi_federal_registry: string;
  };
  lat: number;
  lon: number;
}

export interface SeasonStats {
  avg_t_max_c: number;
  avg_t_min_c: number;
  max_t_c: number;
  min_t_c: number;
  avg_precip_per_day_mm: number;
  total_precip_mm: number;
  days_observed: number;
}

export interface SeasonalWeather {
  seasons: {
    winter: SeasonStats | null;
    spring: SeasonStats | null;
    summer: SeasonStats | null;
    autumn: SeasonStats | null;
  };
  period: string;
  model: string;
  source: string;
  note: string;
}

export interface HydrologyNearest {
  subtype: "river" | "stream" | "lake_or_pond" | "canal" | null;
  name: string | null;
  distance_m: number;
}

export interface Hydrology {
  nearest: HydrologyNearest[];
  flood_risk_flag: boolean;
  note: string;
}

export interface GeotechRisk {
  seismic_intensity_balls: number | null;
  seismic_label: string;
  seismic_description: string;
  permafrost: boolean;
  industrial_within_500m: number;
  industrial_contamination_flag: boolean;
  note: string;
}

// P2 (#46) — cad_buildings соседи + overlap
export interface NeighborBuilding {
  cad_num: string;
  building_name: string | null;
  floors: string | null;
  floors_parsed: number | null;
  year_built: number | null;
  area_m2: number | null;
  cost_per_m2: number | null;
  distance_m: number;
  readable_address: string | null;
}

export interface OverlapBuilding {
  cad_num: string;
  building_name: string | null;
  floors: string | null;
  readable_address: string | null;
  overlap_m2: number | null;
}

export interface NeighborsSummary {
  data_available: boolean;
  radius_m?: number;
  count_buildings_100m?: number;
  avg_floors_100m?: number | null;
  max_floors_100m?: number | null;
  median_cost_per_m2_100m?: number | null;
  neighbors?: NeighborBuilding[];
  has_existing_buildings?: boolean;
  overlap_buildings?: OverlapBuilding[];
  note?: string;
}

export interface MarketTrend {
  recent_avg_price_per_m2: number;
  prior_avg_price_per_m2: number;
  delta_6m_pct: number;
  recent_deals_count: number;
  prior_deals_count: number;
  label: string;
  radius_km: number;
}

// D4 (#36) — 24-month project pipeline competition
export interface PipelineQuarterSlot {
  quarter: string;
  objects: number;
  flats: number;
}

export interface PipelineObject {
  obj_id: number;
  comm_name: string | null;
  dev_name: string | null;
  obj_class: string | null;
  flat_count: number | null;
  ready_dt: string | null;
  // backend имеет explicit `is not None` guard для distance_m (centroid-on-
  // building даёт 0.0 которое falsy, raw Decimal иначе упал бы в JSON), так
  // что nullable отражает defensive Python path.
  distance_m: number | null;
}

export interface Pipeline24mo {
  objects_count: number;
  flats_total: number;
  by_class: Record<string, number>;
  by_quarter: PipelineQuarterSlot[];
  severity: "none" | "low" | "medium" | "high";
  severity_label?: string;
  top_objects: PipelineObject[];
  radius_km?: number;
  horizon_months?: number;
  note?: string;
}

// D2 (#34) — velocity-score: темп продаж конкурентов
export interface VelocityBucketStat {
  units: number;
  sqm: number;
  complexes_count: number;
}

export interface VelocityCompetitor {
  obj_id: number;
  name: string | null;
  obj_class: string | null;
  distance_m: number;
  total_sqm_period: number;
  dev_name?: string | null;
  district_name?: string | null;
  by_room_bucket?: Record<string, number>;
}

export interface VelocityPeriod {
  start: string; // YYYY-MM
  end: string;
}

export interface Velocity {
  competitors_count: number;
  monthly_velocity_sqm: number;
  ekb_median_sqm: number;
  velocity_score: number; // 0..1
  confidence: "high" | "medium" | "low";
  months_observed: number;
  period: VelocityPeriod;
  sample_competitors: VelocityCompetitor[];
  by_room_bucket?: Record<string, VelocityBucketStat>;
  // True если ≥1 конкурент имеет маппинг в objective_complex_mapping.
  // False → конкуренты найдены, velocity=0, данных Objective нет.
  velocity_data_available?: boolean;
  // SF#17: источник данных velocity.
  // 'objective' — Objective (основной), 'rosreestr_fallback' — кадастровый квартал,
  // 'none' — нет данных.
  velocity_source?: "objective" | "rosreestr_fallback" | "none";
}

// G5 (#32) — Gate verdict: can_build_mkd
export type GateVerdictSource = "nspd_dump" | "nspd_dump_partial" | "no_data";

export type GateVerdictLabel =
  | "Можно"
  | "Нельзя"
  | "С ограничениями"
  | "Нужна проверка";

export interface GateBlocker {
  code: string;
  detail: string;
}

export interface GateWarning {
  code: string;
  detail: string;
}

export interface GateVerdict {
  can_build_mkd: boolean | "unknown";
  verdict_label: GateVerdictLabel;
  blockers: GateBlocker[];
  warnings: GateWarning[];
  checks_performed: string[];
  source: GateVerdictSource;
}

export interface ParcelLocation {
  distance_to_center_km: number;
  center_bonus: number;
  ekb_center: { lat: number; lon: number };
  note: string;
}

// P1 (#45) — physical suitability участка.
// label — base value один из BaseLabel'ов либо combo "микро, <first-penalty>"
export type GeometrySuitabilityBaseLabel =
  | "микро"
  | "подходящий"
  | "сложная форма"
  | "слабо подходит";

export interface GeometrySuitability {
  data_available: boolean;
  area_ha?: number;
  area_m2?: number;
  perimeter_m?: number;
  aspect_ratio?: number;
  convex_hull_ratio?: number;
  min_inscribed_rect_dim_m?: number;
  suitability_score?: number;
  // string — допускаем combo-label "микро, узкий"; см. GeometrySuitabilityBaseLabel
  label?: string;
  penalties?: string[];
  recommendation?: string;
  note: string;
}

export interface SuccessRankingBucket {
  bucket: string;
  success_score: number;
  n_deals: number;
  avg_price_per_m2: number | null;
  avg_area_m2: number | null;
}

export interface ParcelSuccessRecommendation {
  district: string;
  /** SF-20: strong = ≥30 сделок в группе; weak = 15-29 сделок (ориентировочно) */
  data_confidence: "strong" | "weak";
  ranking: SuccessRankingBucket[];
  top_bucket: SuccessRankingBucket;
  note: string;
}

// X1 (#47) — per-factor breakdown с verbal explain
export interface FactorContribution {
  factor: string;
  category: string;
  category_ru: string;
  group: string;
  value: number;
  weight: number;
  contribution: number;
  contribution_pct: number;
  verbal: string;
  lat: number | null;
  lon: number | null;
}

export interface ScoreGroupTotal {
  group: string;
  contribution: number;
  count: number;
  contribution_pct: number;
}

export interface ParcelAnalysis {
  cad_num: string;
  source: "cad_quarter" | "cad_building";
  geom_geojson: Geometry | null;
  district: ParcelAnalysisDistrict | null;
  score: number;
  score_label?: "плохо" | "средне" | "хорошо" | "отлично";
  score_max_reference?: number;
  score_explanation?: string;
  market_trend?: MarketTrend | null;
  score_breakdown: Record<string, ParcelAnalysisPoi[]>;
  score_breakdown_detailed?: FactorContribution[];
  score_top_3_positives?: FactorContribution[];
  score_top_3_negatives?: FactorContribution[];
  score_by_group?: ScoreGroupTotal[];
  poi_count: number;
  competitors: ParcelAnalysisCompetitor[];
  noise: ParcelAnalysisNoise | null;
  air_quality: ParcelAnalysisAirQuality | null;
  wind: ParcelAnalysisWind | null;
  weather?: ParcelAnalysisWeather | null;
  seasonal_weather?: SeasonalWeather | null;
  hydrology?: Hydrology;
  geotech_risk?: GeotechRisk;
  geology?: ParcelAnalysisGeology;
  isochrones_available?: boolean;
  score_without_center?: number;
  location?: ParcelLocation;
  success_recommendation?: ParcelSuccessRecommendation | null;
  // P1 (#45) — physical suitability участка
  geometry_suitability?: GeometrySuitability;
  // P2 (#46) — cad_buildings соседи + overlap check
  neighbors_summary?: NeighborsSummary;
  // X2 (#48) — confidence indicator
  confidence?: number;
  confidence_label?: "high" | "medium" | "low";
  confidence_breakdown?: Record<string, number>;
  confidence_caveats?: string[];
  // D4 (#36) — 24-month project pipeline competition
  pipeline_24mo?: Pipeline24mo;
  // G5 (#32) — gate verdict: МКД buildability
  gate_verdict?: GateVerdict;
  // D2 (#34) — velocity-score: темп продаж конкурентов
  velocity?: Velocity | null;
  // Issue #202 — NSPD frontend integration
  nspd_zoning?: import("./nspd").NspdZoning | null;
  nspd_zouit_overlaps?: import("./nspd").NspdZouitOverlap[];
  nspd_engineering_nearby?: import("./nspd").NspdEngineeringNearby[];
  nspd_risk_zones?: import("./nspd").RiskZone[];
  // Issue #94 PR2 — TIER 4 opportunity layers + red lines
  nspd_opportunity_parcels?: import("./nspd").OpportunityParcel[];
  nspd_red_lines?: import("./nspd").RedLine[];
  nspd_dump?: import("./nspd").NspdDumpMeta | null;
  // B5 extended (added 2026-05-18 — expose в legacy Обзор)
  egrn?: {
    address?: string | null;
    permitted_use_text?: string | null;
    land_category?: string | null;
    parcel_status?: string | null;
    right_type?: string | null;
    cadastral_value_rub?: number | null;
    cost_per_m2_rub?: number | null;
    last_egrn_update_date?: string | null;
  } | null;
  utilities?: {
    summary?: Array<{
      subtype: string;
      nearest_m: number;
      name?: string | null;
      count_within_2km?: number;
    }>;
    power_line_охранная_зона_flag?: boolean;
    note?: string | null;
  } | null;
}

export type PoiCategory =
  | "school"
  | "kindergarten"
  | "pharmacy"
  | "hospital"
  | "shop_mall"
  | "shop_supermarket"
  | "shop_small"
  | "park"
  | "tram_stop"
  | "bus_stop"
  | "metro_stop";
