"use client";

import { useCallback, useEffect, useId, useMemo, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { normalizePueblo, PR_MUNICIPALITIES } from "@/lib/pr-municipalities";

type Props = {
  counts?: Record<string, number>;
  paramKey?: string;
  label?: string;
  /** Ruta base para filtros (por defecto la página actual) */
  pathname?: string;
};

type GeoCollection = {
  type: string;
  features: Array<{
    type: string;
    properties?: { NAME?: string };
    geometry: unknown;
  }>;
};

type BrandPalette = {
  bg: string;
  effect: string;
  orb: string;
  surface: string;
};

function cssVar(name: string, fallback: string) {
  if (typeof window === "undefined") return fallback;
  return (
    getComputedStyle(document.documentElement)
      .getPropertyValue(name)
      .trim() || fallback
  );
}

function readPalette(): BrandPalette {
  return {
    bg: cssVar("--bg", "#0A0A0A"),
    effect: cssVar("--effect", "#C5FF00"),
    orb: cssVar("--orb", "#2A3B00"),
    surface: cssVar("--surface", "#141814"),
  };
}

function hexToRgb(hex: string): [number, number, number] | null {
  const h = hex.replace("#", "").trim();
  if (/^[0-9a-fA-F]{3}$/.test(h)) {
    return [
      parseInt(h[0] + h[0], 16),
      parseInt(h[1] + h[1], 16),
      parseInt(h[2] + h[2], 16),
    ];
  }
  if (/^[0-9a-fA-F]{6}$/.test(h)) {
    return [
      parseInt(h.slice(0, 2), 16),
      parseInt(h.slice(2, 4), 16),
      parseInt(h.slice(4, 6), 16),
    ];
  }
  return null;
}

function mixHex(a: string, b: string, t: number) {
  const A = hexToRgb(a);
  const B = hexToRgb(b);
  if (!A || !B) return b;
  const m = (x: number, y: number) => Math.round(x + (y - x) * t);
  const to = (n: number) => n.toString(16).padStart(2, "0");
  return `#${to(m(A[0], B[0]))}${to(m(A[1], B[1]))}${to(m(A[2], B[2]))}`;
}

function fillForCount(
  count: number,
  max: number,
  selected: boolean,
  palette: BrandPalette
) {
  if (selected) return palette.effect;
  // Empty: soft branding tint (no black plate behind the island)
  if (!count || max <= 0) {
    return mixHex(palette.surface, palette.effect, 0.18);
  }
  const t = count / max;
  if (t > 0.66) return mixHex(palette.orb, palette.effect, 0.72);
  if (t > 0.33) return mixHex(palette.orb, palette.effect, 0.42);
  return mixHex(palette.surface, palette.effect, 0.32);
}

export function PuertoRicoPueblosMap({
  counts = {},
  paramKey = "city",
  label = "Filtrar por pueblo",
  pathname: pathnameProp,
}: Props) {
  const mapDomId = `pr-pueblos-${useId().replace(/:/g, "")}`;
  const router = useRouter();
  const pathnameHook = usePathname();
  const pathname = pathnameProp ?? pathnameHook;
  const searchParams = useSearchParams();
  const selected = searchParams.get(paramKey) || "";
  const [hover, setHover] = useState<string | null>(null);
  const [status, setStatus] = useState<"loading" | "ready" | "error">(
    "loading"
  );

  const maxCount = useMemo(
    () => Math.max(0, ...Object.values(counts), 0),
    [counts]
  );
  const countsKey = useMemo(() => JSON.stringify(counts), [counts]);

  const setCity = useCallback(
    (city: string) => {
      const params = new URLSearchParams(searchParams.toString());
      if (!city || normalizePueblo(city) === normalizePueblo(selected)) {
        params.delete(paramKey);
      } else {
        params.set(paramKey, city);
      }
      const qs = params.toString();
      router.push(qs ? `${pathname}?${qs}` : pathname);
    },
    [searchParams, selected, paramKey, pathname, router]
  );

  useEffect(() => {
    let cancelled = false;
    let map: import("leaflet").Map | null = null;

    (async () => {
      try {
        const L = await import("leaflet");
        await import("leaflet/dist/leaflet.css");

        const el = document.getElementById(mapDomId);
        if (!el || cancelled) return;

        const palette = readPalette();
        el.innerHTML = "";
        el.style.background = "transparent";

        map = L.map(el, {
          center: [18.22, -66.4],
          zoom: 8,
          minZoom: 7,
          maxZoom: 11,
          scrollWheelZoom: false,
          attributionControl: false,
          zoomControl: false,
        });

        const container = map.getContainer();
        container.style.background = "transparent";
        const pane = container.querySelector(".leaflet-pane") as HTMLElement | null;
        if (pane) pane.style.background = "transparent";
        const mapPane = container.querySelector(
          ".leaflet-map-pane"
        ) as HTMLElement | null;
        if (mapPane) mapPane.style.background = "transparent";
        const tilePane = container.querySelector(
          ".leaflet-tile-pane"
        ) as HTMLElement | null;
        if (tilePane) tilePane.style.background = "transparent";
        const overlayPane = container.querySelector(
          ".leaflet-overlay-pane"
        ) as HTMLElement | null;
        if (overlayPane) overlayPane.style.background = "transparent";

        map.fitBounds(
          [
            [17.85, -67.35],
            [18.55, -65.2],
          ],
          { padding: [16, 16] }
        );

        const res = await fetch("/data/pr-municipalities.geojson");
        const geojson = (await res.json()) as GeoCollection;
        if (cancelled || !map) return;

        const layer = L.geoJSON(geojson as never, {
          style: (feature) => {
            const name = String(feature?.properties?.NAME || "");
            const count = counts[name] || 0;
            const isSel =
              !!selected &&
              normalizePueblo(selected) === normalizePueblo(name);
            const fill = fillForCount(count, maxCount, isSel, palette);
            return {
              fillColor: fill,
              weight: 0,
              opacity: 0,
              color: fill,
              fillOpacity: 1,
              stroke: false,
            };
          },
          onEachFeature: (feature, lyr) => {
            const name = String(feature.properties?.NAME || "");
            const count = counts[name] || 0;
            const path = lyr as import("leaflet").Path;

            path.on({
              mouseover: (e) => {
                setHover(name);
                const target = e.target as import("leaflet").Path;
                target.setStyle({
                  fillColor: palette.effect,
                  fillOpacity: 1,
                  weight: 0,
                  opacity: 0,
                  color: palette.effect,
                });
                target.bringToFront();
              },
              mouseout: (e) => {
                setHover(null);
                const isSel =
                  !!selected &&
                  normalizePueblo(selected) === normalizePueblo(name);
                const fill = fillForCount(count, maxCount, isSel, palette);
                const target = e.target as import("leaflet").Path;
                target.setStyle({
                  fillColor: fill,
                  fillOpacity: 1,
                  weight: 0,
                  opacity: 0,
                  color: fill,
                });
              },
              click: () => setCity(name),
            });
          },
        });

        layer.addTo(map);
        map.invalidateSize();
        requestAnimationFrame(() => map?.invalidateSize());
        setTimeout(() => map?.invalidateSize(), 150);
        if (!cancelled) setStatus("ready");
      } catch {
        if (!cancelled) setStatus("error");
      }
    })();

    return () => {
      cancelled = true;
      if (map) {
        map.remove();
        map = null;
      }
    };
  }, [selected, maxCount, countsKey, setCity, counts, mapDomId]);

  const displayName = hover || selected || "Selecciona un municipio";

  return (
    <div className="pr-pueblos-map">
      <div className="pr-pueblos-map__bar">
        <div>
          <p className="pr-pueblos-map__label">{label}</p>
          <p className="pr-pueblos-map__name">{displayName}</p>
        </div>
        <div className="pr-pueblos-map__actions">
          <select
            className="input pr-pueblos-map__select"
            value={
              PR_MUNICIPALITIES.find(
                (m) => normalizePueblo(m) === normalizePueblo(selected)
              ) || ""
            }
            onChange={(e) => setCity(e.target.value)}
            aria-label="Municipio"
          >
            <option value="">Todos los pueblos</option>
            {PR_MUNICIPALITIES.map((m) => (
              <option key={m} value={m}>
                {m}
                {counts[m] ? ` (${counts[m]})` : ""}
              </option>
            ))}
          </select>
          {selected ? (
            <button
              type="button"
              className="btn-ghost !px-3 !py-2 text-xs"
              onClick={() => setCity("")}
            >
              Limpiar
            </button>
          ) : null}
        </div>
      </div>
      <div className="pr-pueblos-map__canvas">
        <div id={mapDomId} className="pr-pueblos-map__leaflet" />
        {status === "loading" && (
          <div className="pr-pueblos-map__overlay">
            Cargando mapa de municipios…
          </div>
        )}
        {status === "error" && (
          <div className="pr-pueblos-map__overlay">
            No se pudo cargar el mapa. Usa el selector de pueblo.
          </div>
        )}
      </div>
      <p className="pr-pueblos-map__hint">
        Toca un pueblo para filtrar. Intensidad = cantidad de resultados.
      </p>
    </div>
  );
}
