"use client";

/**
 * MarketLayers — #999 (958-B4): рыночные слои поверх карты Site Finder.
 *
 * Независимо-переключаемые слои (видимость управляется из SiteMap, как у
 * ConnectionPointsLayer):
 *   1. Конкуренты              — CircleMarker на каждый competitor с координатами.
 *   2. Будущие проекты          — CircleMarker на каждый pipeline_24mo.top_objects
 *                                 (§12.1 future supply; dashed-кольцо, viz-5).
 *   3. Зоны риска               — GeoJSON-полигоны из RiskZone.geom_wkt (§13).
 *   4. Перспективные ЗУ          — GeoJSON-полигоны из OpportunityParcel.geom_wkt
 *                                 (§12.1: auction/scheme/free/future ЗУ + ООПТ).
 *   5. Красные линии            — GeoJSON-линии из RedLine.geom_wkt (§13 граддок).
 *
 * Цвета — token-hex (документированное исключение карты/чартов, ui-tokens.md):
 *   Конкуренты      → --viz-2  (#0ea5e9)
 *   Будущие проекты → --viz-5  (#8b5cf6)
 *   Зоны риска      → --danger (#b3261e)
 *   Перспективные ЗУ → --viz-3 (#14b8a6)  — «возможность», отлично от риска
 *   Красные линии   → --warn   (#9a6700)  — граддок-ограничение, не риск-зона
 *
 * future-ЖК (newbuilding_listings) и полноценные граддок-полигоны
 * (planning_projects / ППТ-ПМТ) — ВНЕ scope: эти объекты пока НЕ отдаются в
 * /analyze payload. Слои добавятся после exposure соответствующих API.
 *
 * Graceful: объекты без координат пропускаются; пустые массивы → пустой слой
 * (без падения); невалидный/неподдержанный WKT → фича не рисуется.
 */

import { CircleMarker, GeoJSON, LayerGroup, Popup } from "react-leaflet";
import type { Feature } from "geojson";

import { wktToGeometry } from "@/lib/wkt";
import type {
  ParcelAnalysisCompetitor,
  PipelineObject,
} from "@/types/site-finder";
import type { OpportunityParcel, RedLine, RiskZone } from "@/types/nspd";

// ---------------------------------------------------------------------------
// Market colors — token-hex (map/chart exception per ui-tokens.md)
// ---------------------------------------------------------------------------

export const MARKET_COLORS = {
  competitor: "#0ea5e9", // --viz-2
  pipeline: "#8b5cf6", // --viz-5
  risk: "#b3261e", // --danger
  opportunity: "#14b8a6", // --viz-3 (перспективные ЗУ — «возможность»)
  redline: "#9a6700", // --warn (красные линии застройки — граддок)
} as const;

// ---------------------------------------------------------------------------
// RU labels for opportunity-parcel layers (NSPD `layer` codes → человекочитаемо)
// ---------------------------------------------------------------------------

const OPPORTUNITY_LAYER_LABELS: Record<string, string> = {
  auction_parcels: "ЗУ на торгах",
  scheme_parcels: "ЗУ по схеме размещения",
  free_parcels: "Свободный ЗУ",
  future_parcels: "Перспективный ЗУ",
  oopt: "ООПТ",
};

function opportunityLabel(layer: string): string {
  return OPPORTUNITY_LAYER_LABELS[layer] ?? "Перспективный ЗУ";
}

// ---------------------------------------------------------------------------
// Formatting helpers (RU)
// ---------------------------------------------------------------------------

function formatDistance(m: number | null | undefined): string | null {
  if (m === null || m === undefined || !Number.isFinite(m)) return null;
  return `${Math.round(m).toLocaleString("ru-RU")} м`;
}

// Бэкенд отдаёт NUMERIC-поля (avg_price_per_m2_rub, avg_area_pd) как СТРОКИ
// («160345», «47.5») — Pydantic v2 сериализует Decimal в строку. Приводим к числу,
// иначе typeof/Number.isFinite-гварды молча роняют поле (попап не показывал цену).
function toFiniteNumber(v: number | string | null | undefined): number | null {
  if (v === null || v === undefined) return null;
  const n = typeof v === "string" ? Number(v) : v;
  return Number.isFinite(n) ? n : null;
}

function formatPrice(rub: number | string | null | undefined): string | null {
  const n = toFiniteNumber(rub);
  if (n === null) return null;
  return `${Math.round(n).toLocaleString("ru-RU")} ₽/м²`;
}

function formatReadyDt(iso: string | null | undefined): string | null {
  if (!iso) return null;
  // Бэкенд отдаёт ISO date (YYYY-MM-DD) — показываем как есть, без таймзонных
  // сюрпризов от Date(). Если формат иной — fallback на сырое значение.
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
  if (!m) return iso;
  return `${m[3]}.${m[2]}.${m[1]}`;
}

// Generic guard — сохраняет исходный тип объекта, сужая lat/lon к number
// (иначе .filter() «съел» бы comm_name/obj_class и т.п.).
function hasCoords<T extends { lat?: number | null; lon?: number | null }>(
  o: T,
): o is T & { lat: number; lon: number } {
  return (
    typeof o.lat === "number" &&
    typeof o.lon === "number" &&
    Number.isFinite(o.lat) &&
    Number.isFinite(o.lon) &&
    // (0,0) — Атлантика: на наших данных = «нет координат», пропускаем.
    !(o.lat === 0 && o.lon === 0)
  );
}

// ---------------------------------------------------------------------------
// Layer styles
// ---------------------------------------------------------------------------

const COMPETITOR_RADIUS = 7;
const PIPELINE_RADIUS = 7;

// ---------------------------------------------------------------------------
// Props
// ---------------------------------------------------------------------------

export interface MarketLayersProps {
  competitors: ParcelAnalysisCompetitor[];
  pipelineObjects: PipelineObject[];
  riskZones: RiskZone[];
  // §12.1-13 (#958) — opportunity-ЗУ + красные линии (geom_wkt в /analyze).
  opportunityParcels: OpportunityParcel[];
  redLines: RedLine[];
  showCompetitors: boolean;
  showPipeline: boolean;
  showRiskZones: boolean;
  showOpportunity: boolean;
  showRedLines: boolean;
}

export function MarketLayers({
  competitors,
  pipelineObjects,
  riskZones,
  opportunityParcels,
  redLines,
  showCompetitors,
  showPipeline,
  showRiskZones,
  showOpportunity,
  showRedLines,
}: MarketLayersProps) {
  return (
    <>
      {/* Зоны риска — рисуем ПЕРВЫМИ (под точками), как заливку-фон. */}
      {showRiskZones && (
        <LayerGroup>
          {riskZones.map((zone, idx) => {
            if (!zone.geom_wkt) return null;
            const geometry = wktToGeometry(zone.geom_wkt);
            if (!geometry) return null;
            const feature: Feature = {
              type: "Feature",
              geometry,
              properties: {},
            };
            const areaStr =
              zone.intersection_area_sqm != null
                ? `${Math.round(zone.intersection_area_sqm).toLocaleString("ru-RU")} м²`
                : null;
            return (
              <GeoJSON
                // geom_wkt в key — react-leaflet GeoJSON кэширует слой и не
                // реагирует на смену data prop; хеш форсирует remount при смене
                // участка (тот же приём, что у изохрон в SiteMap).
                key={`risk-${idx}-${zone.geom_wkt.slice(0, 24)}`}
                data={feature}
                style={{
                  color: MARKET_COLORS.risk,
                  weight: 1.5,
                  fillColor: MARKET_COLORS.risk,
                  fillOpacity: 0.18,
                  dashArray: "4 3",
                }}
              >
                <Popup>
                  <div
                    style={{ fontSize: 12, lineHeight: 1.55, minWidth: 170 }}
                  >
                    <div style={{ fontWeight: 700, marginBottom: 4 }}>
                      Зона риска
                    </div>
                    <div style={{ marginBottom: 2 }}>
                      {zone.subtype ?? zone.layer}
                    </div>
                    {areaStr && (
                      <div style={{ color: "#374151" }}>
                        Пересечение с участком: <strong>{areaStr}</strong>
                      </div>
                    )}
                  </div>
                </Popup>
              </GeoJSON>
            );
          })}
        </LayerGroup>
      )}

      {/* §12.1 — Перспективные ЗУ (opportunity parcels): GeoJSON-полигоны под
          точками, заливка viz-3. Сюда входят future_parcels (перспективное
          предложение земли), auction/scheme/free ЗУ и ООПТ. */}
      {showOpportunity && (
        <LayerGroup>
          {opportunityParcels.map((parcel, idx) => {
            if (!parcel.geom_wkt) return null;
            const geometry = wktToGeometry(parcel.geom_wkt);
            if (!geometry) return null;
            const feature: Feature = {
              type: "Feature",
              geometry,
              properties: {},
            };
            const distanceStr = formatDistance(parcel.distance_m);
            return (
              <GeoJSON
                key={`opp-${idx}-${parcel.geom_wkt.slice(0, 24)}`}
                data={feature}
                style={{
                  color: MARKET_COLORS.opportunity,
                  weight: 1.5,
                  fillColor: MARKET_COLORS.opportunity,
                  fillOpacity: 0.16,
                }}
              >
                <Popup>
                  <div
                    style={{ fontSize: 12, lineHeight: 1.55, minWidth: 170 }}
                  >
                    <div
                      style={{
                        fontWeight: 700,
                        marginBottom: 4,
                        display: "flex",
                        alignItems: "center",
                        gap: 5,
                      }}
                    >
                      <span
                        style={{
                          display: "inline-block",
                          width: 10,
                          height: 10,
                          borderRadius: 2,
                          background: MARKET_COLORS.opportunity,
                          flexShrink: 0,
                        }}
                      />
                      {opportunityLabel(parcel.layer)}
                    </div>
                    {parcel.cad_num && (
                      <div style={{ marginBottom: 2 }}>
                        <strong>{parcel.cad_num}</strong>
                      </div>
                    )}
                    {distanceStr && (
                      <div style={{ color: "#374151" }}>{distanceStr}</div>
                    )}
                  </div>
                </Popup>
              </GeoJSON>
            );
          })}
        </LayerGroup>
      )}

      {/* §13 — Красные линии застройки (граддок): GeoJSON-линии warn-цвета.
          geom_wkt — LINESTRING/MULTILINESTRING (wkt.ts парсит оба). */}
      {showRedLines && (
        <LayerGroup>
          {redLines.map((line, idx) => {
            if (!line.geom_wkt) return null;
            const geometry = wktToGeometry(line.geom_wkt);
            if (!geometry) return null;
            const feature: Feature = {
              type: "Feature",
              geometry,
              properties: {},
            };
            // Пересекает участок → длина пересечения; иначе → дистанция nearby.
            const intersectStr =
              line.intersection_length_m != null
                ? `${Math.round(line.intersection_length_m).toLocaleString("ru-RU")} м`
                : null;
            const distanceStr = formatDistance(line.distance_m);
            return (
              <GeoJSON
                key={`redline-${idx}-${line.geom_wkt.slice(0, 24)}`}
                data={feature}
                style={{
                  color: MARKET_COLORS.redline,
                  weight: 3,
                  // Линии — без заливки; пунктир отличает от границ объектов.
                  fillOpacity: 0,
                  dashArray: "6 4",
                }}
              >
                <Popup>
                  <div
                    style={{ fontSize: 12, lineHeight: 1.55, minWidth: 170 }}
                  >
                    <div
                      style={{
                        fontWeight: 700,
                        marginBottom: 4,
                        display: "flex",
                        alignItems: "center",
                        gap: 5,
                      }}
                    >
                      <span
                        style={{
                          display: "inline-block",
                          width: 14,
                          height: 0,
                          borderTop: `3px dashed ${MARKET_COLORS.redline}`,
                          flexShrink: 0,
                        }}
                      />
                      Красная линия застройки
                    </div>
                    {intersectStr ? (
                      <div style={{ color: "#374151" }}>
                        Пересекает участок: <strong>{intersectStr}</strong>
                      </div>
                    ) : (
                      distanceStr && (
                        <div style={{ color: "#374151" }}>
                          До участка: <strong>{distanceStr}</strong>
                        </div>
                      )
                    )}
                  </div>
                </Popup>
              </GeoJSON>
            );
          })}
        </LayerGroup>
      )}

      {/* Конкуренты — сплошная заливка viz-2. */}
      {showCompetitors && (
        <LayerGroup>
          {competitors.filter(hasCoords).map((c, idx) => {
            const distanceStr = formatDistance(c.distance_m);
            const priceStr = formatPrice(c.avg_price_per_m2_rub);
            const showSales =
              typeof c.units_sold === "number" ||
              typeof c.units_available === "number";
            return (
              <CircleMarker
                key={`comp-${c.obj_id}-${idx}`}
                center={[c.lat, c.lon]}
                radius={COMPETITOR_RADIUS}
                pathOptions={{
                  color: MARKET_COLORS.competitor,
                  fillColor: MARKET_COLORS.competitor,
                  fillOpacity: 0.85,
                  weight: 1.5,
                }}
              >
                <Popup>
                  <div
                    style={{ fontSize: 12, lineHeight: 1.55, minWidth: 180 }}
                  >
                    <div
                      style={{
                        fontWeight: 700,
                        marginBottom: 4,
                        display: "flex",
                        alignItems: "center",
                        gap: 5,
                      }}
                    >
                      <span
                        style={{
                          display: "inline-block",
                          width: 10,
                          height: 10,
                          borderRadius: "50%",
                          background: MARKET_COLORS.competitor,
                          flexShrink: 0,
                        }}
                      />
                      Конкурент
                    </div>
                    <div style={{ marginBottom: 2 }}>
                      <strong>{c.comm_name ?? "Без названия"}</strong>
                    </div>
                    {c.dev_name && (
                      <div style={{ color: "#6b7280", marginBottom: 2 }}>
                        Застройщик: {c.dev_name}
                      </div>
                    )}
                    {c.obj_class && (
                      <div style={{ color: "#6b7280", marginBottom: 2 }}>
                        Класс: {c.obj_class}
                      </div>
                    )}
                    {distanceStr && (
                      <div style={{ color: "#374151" }}>{distanceStr}</div>
                    )}
                    {c.site_status && (
                      <div style={{ color: "#374151" }}>{c.site_status}</div>
                    )}
                    {priceStr && (
                      <div style={{ color: "#374151" }}>{priceStr}</div>
                    )}
                    {toFiniteNumber(c.avg_area_pd) !== null && (
                      <div style={{ color: "#374151" }}>
                        Ср. площадь кв.: {toFiniteNumber(c.avg_area_pd)} м²
                      </div>
                    )}
                    {showSales && (
                      <div style={{ color: "#374151" }}>
                        Продано: {c.units_sold ?? 0}
                        {typeof c.units_available === "number"
                          ? ` · в продаже: ${c.units_available}`
                          : ""}
                      </div>
                    )}
                  </div>
                </Popup>
              </CircleMarker>
            );
          })}
        </LayerGroup>
      )}

      {/* Будущие проекты (pipeline) — визуально ОТЛИЧНЫ: полое кольцо viz-5
          с пунктирной обводкой (не путать с конкурентами). */}
      {showPipeline && (
        <LayerGroup>
          {pipelineObjects.filter(hasCoords).map((p, idx) => {
            const distanceStr = formatDistance(p.distance_m);
            const readyStr = formatReadyDt(p.ready_dt);
            return (
              <CircleMarker
                key={`pipe-${p.obj_id}-${idx}`}
                center={[p.lat, p.lon]}
                radius={PIPELINE_RADIUS}
                pathOptions={{
                  color: MARKET_COLORS.pipeline,
                  fillColor: MARKET_COLORS.pipeline,
                  fillOpacity: 0.12,
                  weight: 2.5,
                  dashArray: "3 2",
                }}
              >
                <Popup>
                  <div
                    style={{ fontSize: 12, lineHeight: 1.55, minWidth: 180 }}
                  >
                    <div
                      style={{
                        fontWeight: 700,
                        marginBottom: 4,
                        display: "flex",
                        alignItems: "center",
                        gap: 5,
                      }}
                    >
                      <span
                        style={{
                          display: "inline-block",
                          width: 10,
                          height: 10,
                          borderRadius: "50%",
                          border: `2px dashed ${MARKET_COLORS.pipeline}`,
                          boxSizing: "border-box",
                          flexShrink: 0,
                        }}
                      />
                      Будущий проект
                    </div>
                    <div style={{ marginBottom: 2 }}>
                      <strong>{p.comm_name ?? "Без названия"}</strong>
                    </div>
                    {p.obj_class && (
                      <div style={{ color: "#6b7280", marginBottom: 2 }}>
                        Класс: {p.obj_class}
                      </div>
                    )}
                    {typeof p.flat_count === "number" && (
                      <div style={{ color: "#374151" }}>
                        Квартир: {p.flat_count.toLocaleString("ru-RU")}
                      </div>
                    )}
                    {readyStr && (
                      <div style={{ color: "#374151" }}>Сдача: {readyStr}</div>
                    )}
                    {distanceStr && (
                      <div style={{ color: "#374151" }}>{distanceStr}</div>
                    )}
                  </div>
                </Popup>
              </CircleMarker>
            );
          })}
        </LayerGroup>
      )}
    </>
  );
}
