"use client";

import { useState, useRef, useCallback, useEffect } from "react";
import dynamic from "next/dynamic";
import { Map as MapIcon, Loader2, AlertTriangle, RefreshCw } from "lucide-react";
import { Button } from "@/shared/components/ui/button";
import { Card, CardContent } from "@/shared/components/ui/card";
import { Badge } from "@/shared/components/ui/badge";
import { BasemapSwitcher } from "@/modules/geoportal/components/basemap-switcher";
import {
  SelectionToolbar,
  type SelectionMode,
} from "@/modules/geoportal/components/selection-toolbar";
import { FeatureInfoPanel } from "@/modules/geoportal/components/feature-info-panel";
import type { MapViewerHandle } from "@/modules/geoportal/components/map-viewer";
import type {
  BasemapId,
  ClickedFeature,
  LayerVisibility,
  SelectedFeature,
} from "@/modules/geoportal/types";

/* MapLibre uses WebGL — must disable SSR */
const MapViewer = dynamic(
  () =>
    import("@/modules/geoportal/components/map-viewer").then((m) => ({
      default: m.MapViewer,
    })),
  {
    ssr: false,
    loading: () => (
      <div className="flex items-center justify-center h-64 bg-muted/30 rounded-lg">
        <p className="text-sm text-muted-foreground">Se incarca harta...</p>
      </div>
    ),
  },
);

/* ------------------------------------------------------------------ */
/*  Layer IDs — must match map-viewer.tsx LAYER_IDS                     */
/* ------------------------------------------------------------------ */

const BASE_LAYERS = [
  "l-terenuri-fill",
  "l-terenuri-line",
  "l-terenuri-label",
  "l-cladiri-fill",
  "l-cladiri-line",
];

/* ------------------------------------------------------------------ */
/*  Props                                                              */
/* ------------------------------------------------------------------ */

type MapTabProps = {
  siruta: string;
  sirutaValid: boolean;
  sessionConnected: boolean;
  syncLocalCount: number; // total local features for this UAT
  onSyncRefresh: () => void;
};

/* ------------------------------------------------------------------ */
/*  Typed map handle                                                    */
/* ------------------------------------------------------------------ */

type MapLike = {
  getLayer(id: string): unknown;
  getSource(id: string): unknown;
  addSource(id: string, source: Record<string, unknown>): void;
  addLayer(layer: Record<string, unknown>, before?: string): void;
  setFilter(id: string, filter: unknown[] | null): void;
  setLayoutProperty(id: string, prop: string, value: unknown): void;
  setPaintProperty(id: string, prop: string, value: unknown): void;
  fitBounds(
    bounds: [number, number, number, number],
    opts?: Record<string, unknown>,
  ): void;
  isStyleLoaded(): boolean;
};

function asMap(handle: MapViewerHandle | null): MapLike | null {
  const m = handle?.getMap();
  return m ? (m as unknown as MapLike) : null;
}

/* ------------------------------------------------------------------ */
/*  Component                                                          */
/* ------------------------------------------------------------------ */

export function MapTab({ siruta, sirutaValid, sessionConnected, syncLocalCount, onSyncRefresh }: MapTabProps) {
  const mapHandleRef = useRef<MapViewerHandle>(null);
  const [basemap, setBasemap] = useState<BasemapId>("liberty");
  const [clickedFeature, setClickedFeature] =
    useState<ClickedFeature | null>(null);
  const [selectionMode, setSelectionMode] = useState<SelectionMode>("off");
  const [selectedFeatures, setSelectedFeatures] = useState<SelectedFeature[]>(
    [],
  );
  const [boundsLoading, setBoundsLoading] = useState(false);
  const [mapReady, setMapReady] = useState(false);
  const appliedSirutaRef = useRef("");
  const boundsRef = useRef<[number, number, number, number] | null>(null);
  const prevCheckSirutaRef = useRef("");
  const boundsFittedForSirutaRef = useRef("");

  /* Boundary check results */
  const [mismatchSummary, setMismatchSummary] = useState<{
    foreign: number;
    edge: number;
  } | null>(null);

  /* Quick sync state */
  const [syncing, setSyncing] = useState(false);
  const [syncMsg, setSyncMsg] = useState("");

  /* Layer visibility: show terenuri + cladiri, hide admin */
  const [layerVisibility] = useState<LayerVisibility>({
    terenuri: true,
    cladiri: true,
    administrativ: false,
  });

  /* ── Detect when map is ready (also re-detects after basemap switch) ── */
  useEffect(() => {
    if (!sirutaValid) return;
    const check = setInterval(() => {
      const map = asMap(mapHandleRef.current);
      if (!map || !map.isStyleLoaded()) {
        // Map destroyed (basemap switch) — reset so effects re-run
        if (mapReady) {
          setMapReady(false);
          appliedSirutaRef.current = "";
          prevCheckSirutaRef.current = "";
        }
        return;
      }
      // Map is ready — check if our custom source exists
      // If not (new map instance after basemap switch), reset and re-apply
      if (mapReady && !map.getSource("gis_terenuri_status")) {
        appliedSirutaRef.current = "";
        prevCheckSirutaRef.current = "";
        setMapReady(false);
        // Small delay to let the new map fully initialize
        setTimeout(() => setMapReady(true), 100);
      } else if (!mapReady) {
        setMapReady(true);
      }
    }, 300);
    return () => clearInterval(check);
  }, [sirutaValid, mapReady]);

  /* ── Hide basemap admin boundaries + our UAT layers (we use siruta filter) */
  const cleanedBasemapRef = useRef(false);
  useEffect(() => {
    if (!mapReady) {
      cleanedBasemapRef.current = false;
      return;
    }
    if (cleanedBasemapRef.current) return;
    const map = asMap(mapHandleRef.current);
    if (!map) return;
    cleanedBasemapRef.current = true;

    // Hide OpenFreeMap admin boundary and place layers (redundant — we have our own UATs)
    try {
      const style = (map as unknown as { getStyle(): { layers?: { id: string }[] } }).getStyle();
      if (style?.layers) {
        for (const layer of style.layers) {
          const id = layer.id.toLowerCase();
          if (
            id.includes("boundary") ||
            id.includes("admin") ||
            (id.includes("place") && !id.includes("place-city") && !id.includes("place-town"))
          ) {
            map.setLayoutProperty(layer.id, "visibility", "none");
          }
        }
      }
    } catch {
      /* noop */
    }

    // Hide our Martin UAT layers (not needed when filtering by siruta)
    const uatLayers = [
      "l-uats-z0-line", "l-uats-z5-fill", "l-uats-z5-line",
      "l-uats-z8-fill", "l-uats-z8-line", "l-uats-z8-label",
      "l-uats-z12-fill", "l-uats-z12-line", "l-uats-z12-label",
    ];
    for (const lid of uatLayers) {
      try { if (map.getLayer(lid)) map.setLayoutProperty(lid, "visibility", "none"); } catch { /* noop */ }
    }
  }, [mapReady]);

  /* ── Fetch UAT bounds ──────────────────────────────────────── */
  const prevBoundsSirutaRef = useRef("");
  useEffect(() => {
    if (!sirutaValid || !siruta) return;
    if (prevBoundsSirutaRef.current === siruta) return;
    prevBoundsSirutaRef.current = siruta;

    setBoundsLoading(true);
    fetch(`/api/geoportal/uat-bounds?siruta=${siruta}`)
      .then((r) => (r.ok ? r.json() : null))
      .then(
        (data: { bounds?: [[number, number], [number, number]] } | null) => {
          if (data?.bounds) {
            const [[minLng, minLat], [maxLng, maxLat]] = data.bounds;
            boundsRef.current = [minLng, minLat, maxLng, maxLat];
            boundsFittedForSirutaRef.current = ""; // reset — need to fit for new siruta
            const map = asMap(mapHandleRef.current);
            if (map) {
              map.fitBounds([minLng, minLat, maxLng, maxLat], {
                padding: 40,
                duration: 1500,
              });
              boundsFittedForSirutaRef.current = siruta;
            }
          }
        },
      )
      .catch(() => {})
      .finally(() => setBoundsLoading(false));
  }, [siruta, sirutaValid]);

  /* ── When map becomes ready, fitBounds ONCE per siruta ──────── */
  useEffect(() => {
    if (!mapReady || !boundsRef.current || !siruta) return;
    // Only fit bounds once per siruta — don't reset zoom on basemap switch or re-render
    if (boundsFittedForSirutaRef.current === siruta) return;
    const map = asMap(mapHandleRef.current);
    if (!map) return;
    map.fitBounds(boundsRef.current, { padding: 40, duration: 1500 });
    boundsFittedForSirutaRef.current = siruta;
  }, [mapReady, siruta]);

  /* ── Apply siruta filter + enrichment overlay ──────────────── */
  useEffect(() => {
    if (!mapReady || !sirutaValid || !siruta) return;
    if (appliedSirutaRef.current === siruta) return;

    const map = asMap(mapHandleRef.current);
    if (!map) return;

    appliedSirutaRef.current = siruta;
    const filter = ["==", ["get", "siruta"], siruta];

    // Filter base layers by siruta
    for (const layerId of BASE_LAYERS) {
      try {
        if (map.getLayer(layerId)) map.setFilter(layerId, filter);
      } catch {
        /* noop */
      }
    }

    // Keep l-terenuri-fill VISIBLE but fully transparent (catches clicks!)
    try {
      if (map.getLayer("l-terenuri-fill"))
        map.setPaintProperty("l-terenuri-fill", "fill-opacity", 0);
    } catch {
      /* noop */
    }

    const martinBase =
      typeof window !== "undefined"
        ? `${window.location.origin}/tiles`
        : "/tiles";

    // ── Enrichment overlay for PARCELS ──
    if (!map.getSource("gis_terenuri_status")) {
      map.addSource("gis_terenuri_status", {
        type: "vector",
        tiles: [`${martinBase}/gis_terenuri_status/{z}/{x}/{y}`],
        minzoom: 10,
        maxzoom: 18,
      });

      // Data-driven fill: red = building no legal, green = enriched, yellow = no enrichment
      map.addLayer(
        {
          id: "l-ps-terenuri-fill",
          type: "fill",
          source: "gis_terenuri_status",
          "source-layer": "gis_terenuri_status",
          minzoom: 13,
          filter,
          paint: {
            "fill-color": [
              "case",
              // Building without legal docs: RED fill (covers building too)
              [
                "all",
                ["==", ["get", "has_building"], 1],
                ["==", ["get", "build_legal"], 0],
              ],
              "#ef4444",
              // Building with legal: light blue
              ["==", ["get", "has_building"], 1],
              "#93c5fd",
              // Enriched, no building: green
              ["==", ["get", "has_enrichment"], 1],
              "#22c55e",
              // No enrichment: amber/yellow
              "#fbbf24",
            ],
            "fill-opacity": [
              "case",
              // Stronger opacity for building issues so it shows through
              [
                "all",
                ["==", ["get", "has_building"], 1],
                ["==", ["get", "build_legal"], 0],
              ],
              0.45,
              0.25,
            ],
          },
        },
        "l-terenuri-fill", // below the transparent click-catcher
      );

      // Data-driven outline: red = building no legal, blue = building legal, green = default
      map.addLayer(
        {
          id: "l-ps-terenuri-line",
          type: "line",
          source: "gis_terenuri_status",
          "source-layer": "gis_terenuri_status",
          minzoom: 13,
          filter,
          paint: {
            "line-color": [
              "case",
              [
                "all",
                ["==", ["get", "has_building"], 1],
                ["==", ["get", "build_legal"], 0],
              ],
              "#ef4444", // red: building without legal
              ["==", ["get", "has_building"], 1],
              "#3b82f6", // blue: building with legal
              "#15803d", // green: no building
            ],
            "line-width": [
              "case",
              ["==", ["get", "has_building"], 1],
              2,
              0.8,
            ],
          },
        },
        "l-terenuri-fill",
      );
    } else {
      try {
        if (map.getLayer("l-ps-terenuri-fill"))
          map.setFilter("l-ps-terenuri-fill", filter);
        if (map.getLayer("l-ps-terenuri-line"))
          map.setFilter("l-ps-terenuri-line", filter);
      } catch {
        /* noop */
      }
    }

    // ── Enrichment overlay for BUILDINGS ──
    if (!map.getSource("gis_cladiri_status")) {
      map.addSource("gis_cladiri_status", {
        type: "vector",
        tiles: [`${martinBase}/gis_cladiri_status/{z}/{x}/{y}`],
        minzoom: 14,
        maxzoom: 18,
      });

      // Data-driven fill: red = no legal docs, blue = has legal docs
      map.addLayer(
        {
          id: "l-ps-cladiri-fill",
          type: "fill",
          source: "gis_cladiri_status",
          "source-layer": "gis_cladiri_status",
          minzoom: 14,
          filter,
          paint: {
            "fill-color": [
              "case",
              ["==", ["get", "build_legal"], 1],
              "#3b82f6", // blue: legal docs OK
              "#ef4444", // red: no legal docs
            ],
            "fill-opacity": 0.55,
          },
        },
        "l-terenuri-fill",
      );

      map.addLayer(
        {
          id: "l-ps-cladiri-line",
          type: "line",
          source: "gis_cladiri_status",
          "source-layer": "gis_cladiri_status",
          minzoom: 14,
          filter,
          paint: {
            "line-color": [
              "case",
              ["==", ["get", "build_legal"], 1],
              "#1e40af", // dark blue: legal
              "#b91c1c", // dark red: no legal
            ],
            "line-width": 1.5,
          },
        },
        "l-terenuri-fill",
      );
    } else {
      try {
        if (map.getLayer("l-ps-cladiri-fill"))
          map.setFilter("l-ps-cladiri-fill", filter);
        if (map.getLayer("l-ps-cladiri-line"))
          map.setFilter("l-ps-cladiri-line", filter);
      } catch {
        /* noop */
      }
    }
  }, [mapReady, siruta, sirutaValid]);

  /* ── Boundary cross-check: load mismatched parcels ─────────── */
  useEffect(() => {
    if (!mapReady || !sirutaValid || !siruta) return;
    if (prevCheckSirutaRef.current === siruta) return;
    prevCheckSirutaRef.current = siruta;

    fetch(`/api/geoportal/boundary-check?siruta=${siruta}`)
      .then((r) => (r.ok ? r.json() : null))
      .then(
        (
          data: {
            type?: string;
            features?: GeoJSON.Feature[];
            summary?: { foreign: number; edge: number };
          } | null,
        ) => {
          if (!data || !data.features || data.features.length === 0) {
            setMismatchSummary(null);
            return;
          }

          setMismatchSummary(data.summary ?? null);

          const map = asMap(mapHandleRef.current);
          if (!map) return;

          // Add or update GeoJSON source for mismatched parcels
          if (map.getSource("boundary-mismatch")) {
            // Update data
            const src = map.getSource("boundary-mismatch") as unknown as {
              setData(d: unknown): void;
            };
            src.setData(data);
          } else {
            map.addSource("boundary-mismatch", {
              type: "geojson",
              data: data as unknown as Record<string, unknown>,
            });

            // Orange dashed fill for mismatched parcels
            map.addLayer({
              id: "l-mismatch-fill",
              type: "fill",
              source: "boundary-mismatch",
              minzoom: 13,
              paint: {
                "fill-color": [
                  "case",
                  ["==", ["get", "mismatch_type"], "foreign"],
                  "#f97316",
                  "#a855f7",
                ],
                "fill-opacity": 0.35,
              },
            });

            map.addLayer({
              id: "l-mismatch-line",
              type: "line",
              source: "boundary-mismatch",
              minzoom: 13,
              paint: {
                "line-color": [
                  "case",
                  ["==", ["get", "mismatch_type"], "foreign"],
                  "#ea580c",
                  "#9333ea",
                ],
                "line-width": 2.5,
                "line-dasharray": [4, 2],
              },
            });

            // Labels — same zoom + font as normal parcel labels
            map.addLayer({
              id: "l-mismatch-label",
              type: "symbol",
              source: "boundary-mismatch",
              minzoom: 16,
              layout: {
                "text-field": ["coalesce", ["get", "cadastral_ref"], ""],
                "text-font": ["Noto Sans Regular"],
                "text-size": 10,
                "text-anchor": "center",
                "text-allow-overlap": false,
                "text-max-width": 8,
              },
              paint: {
                "text-color": [
                  "case",
                  ["==", ["get", "mismatch_type"], "foreign"],
                  "#ea580c",
                  "#9333ea",
                ],
                "text-halo-color": "#ffffff",
                "text-halo-width": 1.5,
              },
            });
          }
        },
      )
      .catch(() => {});
  }, [mapReady, siruta, sirutaValid]);

  /* ── Feature click handler ─────────────────────────────────── */
  const handleFeatureClick = useCallback(
    (feature: ClickedFeature | null) => {
      if (!feature || !feature.properties) {
        setClickedFeature(null);
        return;
      }
      setClickedFeature(feature);
    },
    [],
  );

  /* ── Selection mode handler ────────────────────────────────── */
  const handleSelectionModeChange = useCallback((mode: SelectionMode) => {
    if (mode === "off") {
      mapHandleRef.current?.clearSelection();
      setSelectedFeatures([]);
    }
    setSelectionMode(mode);
  }, []);

  /* ── Quick sync (terenuri + cladiri + intravilan) ──────────── */
  const handleQuickSync = useCallback(async () => {
    if (!siruta || syncing || !sessionConnected) return;
    setSyncing(true);
    setSyncMsg("Se sincronizează...");
    try {
      const res = await fetch("/api/eterra/sync-background", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ siruta, mode: "base" }),
      });
      const data = (await res.json()) as { jobId?: string; error?: string };
      if (data.error) {
        setSyncMsg(`Eroare: ${data.error}`);
      } else {
        setSyncMsg("Sincronizare pornită în fundal. Revino în câteva minute.");
        onSyncRefresh();
      }
    } catch {
      setSyncMsg("Eroare rețea");
    }
    setSyncing(false);
  }, [siruta, syncing, sessionConnected, onSyncRefresh]);

  /* ── Render ─────────────────────────────────────────────────── */

  if (!sirutaValid) {
    return (
      <Card>
        <CardContent className="py-12 text-center text-muted-foreground">
          <MapIcon className="h-10 w-10 mx-auto mb-3 opacity-30" />
          <p>Selectează un UAT din lista de mai sus</p>
        </CardContent>
      </Card>
    );
  }

  /* No data for this UAT — show sync button */
  if (syncLocalCount === 0) {
    return (
      <Card>
        <CardContent className="py-12 text-center space-y-4">
          <MapIcon className="h-10 w-10 mx-auto mb-1 text-muted-foreground opacity-30" />
          <p className="text-muted-foreground">
            Nu există date locale pentru acest UAT.
          </p>
          {sessionConnected ? (
            <div className="space-y-2">
              <Button
                onClick={() => void handleQuickSync()}
                disabled={syncing}
                className="bg-zinc-900 hover:bg-zinc-800 text-white dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
              >
                {syncing ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <RefreshCw className="mr-2 h-4 w-4" />
                )}
                Sincronizează terenuri, clădiri și intravilan
              </Button>
              {syncMsg && (
                <p className="text-xs text-muted-foreground">{syncMsg}</p>
              )}
            </div>
          ) : (
            <p className="text-xs text-muted-foreground">
              Conectează-te la eTerra pentru a sincroniza date.
            </p>
          )}
        </CardContent>
      </Card>
    );
  }

  return (
    <div className="space-y-2">
      {/* Boundary mismatch alert */}
      {mismatchSummary && (mismatchSummary.foreign > 0 || mismatchSummary.edge > 0) && (
        <div className="flex items-center gap-2 rounded-lg border border-orange-200 bg-orange-50/50 dark:border-orange-800 dark:bg-orange-950/20 px-3 py-2 text-xs">
          <AlertTriangle className="h-3.5 w-3.5 text-orange-500 shrink-0" />
          <span>
            <strong>Verificare limită UAT:</strong>{" "}
            {mismatchSummary.foreign > 0 && (
              <>
                <Badge variant="outline" className="text-[10px] border-orange-300 text-orange-700 dark:text-orange-400 mx-0.5">
                  {mismatchSummary.foreign} parcele străine
                </Badge>
                (din alt UAT dar geometric în acest UAT)
              </>
            )}
            {mismatchSummary.foreign > 0 && mismatchSummary.edge > 0 && " · "}
            {mismatchSummary.edge > 0 && (
              <>
                <Badge variant="outline" className="text-[10px] border-purple-300 text-purple-700 dark:text-purple-400 mx-0.5">
                  {mismatchSummary.edge} parcele la limită
                </Badge>
                (înregistrate aici dar centroid în afara limitei)
              </>
            )}
          </span>
        </div>
      )}

      <div className="relative h-[600px] rounded-lg border overflow-hidden">
        {boundsLoading && (
          <div className="absolute top-3 left-1/2 -translate-x-1/2 z-20 flex items-center gap-2 rounded-full bg-background/90 border px-3 py-1.5 text-xs shadow-sm">
            <Loader2 className="h-3 w-3 animate-spin" />
            Se încarcă zona UAT...
          </div>
        )}

        <MapViewer
          ref={mapHandleRef}
          className="h-full w-full"
          basemap={basemap}
          zoom={15}
          selectionType={selectionMode}
          onFeatureClick={handleFeatureClick}
          onSelectionChange={setSelectedFeatures}
          layerVisibility={layerVisibility}
        />

        {/* Top-right: basemap switcher + feature panel */}
        <div className="absolute top-3 right-3 z-10 flex flex-col items-end gap-2">
          <BasemapSwitcher value={basemap} onChange={setBasemap} />
          {clickedFeature && selectionMode === "off" && (
            <FeatureInfoPanel
              feature={clickedFeature}
              onClose={() => setClickedFeature(null)}
            />
          )}
        </div>

        {/* Bottom-left: selection toolbar */}
        <div className="absolute bottom-8 left-3 z-10">
          <SelectionToolbar
            selectedFeatures={selectedFeatures}
            selectionMode={selectionMode}
            onSelectionModeChange={handleSelectionModeChange}
            onClearSelection={() => {
              mapHandleRef.current?.clearSelection();
              setSelectedFeatures([]);
            }}
          />
        </div>

        {/* Top-left: legend (hidden when feature panel is open) */}
        {!clickedFeature && (
        <div className="absolute top-3 left-3 z-10 rounded-lg bg-background/90 border p-2 text-[10px] space-y-1">
          <div className="flex items-center gap-1.5">
            <span
              className="inline-block h-3 w-3 rounded-sm"
              style={{
                backgroundColor: "rgba(251,191,36,0.25)",
                border: "1px solid #15803d",
              }}
            />
            Fără enrichment
          </div>
          <div className="flex items-center gap-1.5">
            <span
              className="inline-block h-3 w-3 rounded-sm"
              style={{
                backgroundColor: "rgba(34,197,94,0.25)",
                border: "1px solid #15803d",
              }}
            />
            Cu enrichment
          </div>
          <div className="flex items-center gap-1.5">
            <span
              className="inline-block h-3 w-3 rounded-sm"
              style={{
                backgroundColor: "rgba(147,197,253,0.25)",
                border: "2px solid #3b82f6",
              }}
            />
            Cu clădire (legal)
          </div>
          <div className="flex items-center gap-1.5">
            <span
              className="inline-block h-3 w-3 rounded-sm"
              style={{
                backgroundColor: "rgba(239,68,68,0.45)",
                border: "2px solid #ef4444",
              }}
            />
            Clădire fără acte
          </div>
          {mismatchSummary && (mismatchSummary.foreign > 0 || mismatchSummary.edge > 0) && (
            <>
              <div className="font-semibold text-[11px] mt-1.5 mb-1">Limită UAT</div>
              <div className="flex items-center gap-1.5">
                <span
                  className="inline-block h-3 w-3 rounded-sm"
                  style={{
                    backgroundColor: "rgba(249,115,22,0.35)",
                    border: "2px dashed #ea580c",
                  }}
                />
                Parcele străine
              </div>
              <div className="flex items-center gap-1.5">
                <span
                  className="inline-block h-3 w-3 rounded-sm"
                  style={{
                    backgroundColor: "rgba(168,85,247,0.35)",
                    border: "2px dashed #9333ea",
                  }}
                />
                La limită
              </div>
            </>
          )}
        </div>
        )}
      </div>
    </div>
  );
}
