"use client";

import {
  useEffect, useRef, useState, useImperativeHandle, forwardRef, useCallback,
} from "react";
import maplibregl from "maplibre-gl";
import { Protocol as PmtilesProtocol } from "pmtiles";
import { cn } from "@/shared/lib/utils";
import type { BasemapId } from "./basemap-switcher";
import type { ClickedFeatureLite } from "./feature-info-panel";

// Ensure MapLibre CSS loaded (static import fails in standalone build)
if (typeof document !== "undefined") {
  const LINK_ID = "maplibre-gl-css";
  if (!document.getElementById(LINK_ID)) {
    const link = document.createElement("link");
    link.id = LINK_ID;
    link.rel = "stylesheet";
    link.href = "/maplibre-gl.css";
    document.head.appendChild(link);
  }
}

// Register PMTiles protocol once
if (typeof window !== "undefined") {
  const w = window as typeof window & { __pmtilesRegistered?: boolean };
  if (!w.__pmtilesRegistered) {
    const proto = new PmtilesProtocol();
    maplibregl.addProtocol("pmtiles", proto.tile);
    w.__pmtilesRegistered = true;
  }
}

const DEFAULT_CENTER: [number, number] = [25.0, 46.0];
const DEFAULT_ZOOM = 6;

const PMTILES_URL =
  process.env.NEXT_PUBLIC_PMTILES_URL ||
  "https://pmtiles.gis.ac/overview.pmtiles";

type BasemapDef =
  | { type: "style"; url: string }
  | { type: "raster"; tiles: string[]; attribution: string; tileSize: number; maxzoom?: number };

const BASEMAPS: Record<BasemapId, BasemapDef> = {
  liberty: { type: "style", url: "https://tiles.openfreemap.org/styles/liberty" },
  dark: { type: "style", url: "https://tiles.openfreemap.org/styles/dark" },
  satellite: {
    type: "raster",
    tiles: [
      "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
    ],
    attribution: '&copy; <a href="https://www.esri.com">Esri</a>, Maxar',
    tileSize: 256,
  },
  google: {
    type: "raster",
    tiles: ["https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}"],
    attribution: "&copy; Google",
    tileSize: 256,
    maxzoom: 20,
  },
};

const PM_SRC = "gis-pmtiles";

function buildStyle(b: BasemapDef): maplibregl.StyleSpecification | string {
  if (b.type === "style") return b.url;
  return {
    version: 8 as const,
    sources: {
      basemap: {
        type: "raster" as const,
        tiles: b.tiles,
        tileSize: b.tileSize,
        attribution: b.attribution,
      },
    },
    layers: [
      {
        id: "basemap-tiles",
        type: "raster" as const,
        source: "basemap",
        minzoom: 0,
        maxzoom: b.maxzoom ?? 19,
      },
    ],
  };
}

export type MapViewerHandle = {
  flyTo: (center: [number, number], zoom?: number) => void;
  getMap: () => maplibregl.Map | null;
};

interface Props {
  basemap: BasemapId;
  onFeatureClick: (f: ClickedFeatureLite | null) => void;
  className?: string;
}

export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
  { basemap, onFeatureClick, className },
  ref,
) {
  const containerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);
  const viewStateRef = useRef({ center: DEFAULT_CENTER, zoom: DEFAULT_ZOOM });
  const [ready, setReady] = useState(false);

  const addGisLayers = useCallback((map: maplibregl.Map) => {
    if (map.getSource(PM_SRC)) return;

    map.addSource(PM_SRC, {
      type: "vector",
      url: `pmtiles://${PMTILES_URL}`,
    });

    // UAT boundaries — visible at every zoom, more prominent on low/mid zoom
    map.addLayer({
      id: "v2-uats-z5",
      type: "line",
      source: PM_SRC,
      "source-layer": "gis_uats_z5",
      minzoom: 0,
      maxzoom: 8,
      paint: {
        "line-color": "#9ca3af",
        "line-width": 0.8,
        "line-opacity": 0.6,
      },
    });
    map.addLayer({
      id: "v2-uats-z8",
      type: "line",
      source: PM_SRC,
      "source-layer": "gis_uats_z8",
      minzoom: 8,
      maxzoom: 13,
      paint: {
        "line-color": "#6b7280",
        "line-width": 1.2,
        "line-opacity": 0.7,
      },
    });

    // Buildings — fill + outline
    map.addLayer({
      id: "v2-cladiri-fill",
      type: "fill",
      source: PM_SRC,
      "source-layer": "gis_cladiri",
      minzoom: 13,
      paint: {
        "fill-color": "#fb923c",
        "fill-opacity": 0.25,
      },
    });
    map.addLayer({
      id: "v2-cladiri-line",
      type: "line",
      source: PM_SRC,
      "source-layer": "gis_cladiri",
      minzoom: 13,
      paint: {
        "line-color": "#ea580c",
        "line-width": 0.6,
      },
    });

    // Parcels (terenuri) — line outline only
    map.addLayer({
      id: "v2-terenuri-line",
      type: "line",
      source: PM_SRC,
      "source-layer": "gis_terenuri",
      minzoom: 13,
      paint: {
        "line-color": "#0ea5e9",
        "line-width": 0.8,
        "line-opacity": 0.85,
      },
    });
    // Invisible fill for click hit-testing
    map.addLayer({
      id: "v2-terenuri-hit",
      type: "fill",
      source: PM_SRC,
      "source-layer": "gis_terenuri",
      minzoom: 13,
      paint: {
        "fill-color": "#0ea5e9",
        "fill-opacity": 0.001,
      },
    });
  }, []);

  // Initialize / rebuild on basemap change
  useEffect(() => {
    if (!containerRef.current) return;
    const def = BASEMAPS[basemap];
    setReady(false);

    const map = new maplibregl.Map({
      container: containerRef.current,
      style: buildStyle(def),
      center: viewStateRef.current.center,
      zoom: viewStateRef.current.zoom,
      maxZoom: 19,
      attributionControl: { compact: true },
    });

    mapRef.current = map;

    map.on("moveend", () => {
      const c = map.getCenter();
      viewStateRef.current = {
        center: [c.lng, c.lat],
        zoom: map.getZoom(),
      };
    });

    map.on("load", () => {
      addGisLayers(map);
      setReady(true);
    });

    // Click handler — prioritize terenuri, then cladiri
    const onClick = (e: maplibregl.MapMouseEvent) => {
      const feats = map.queryRenderedFeatures(e.point, {
        layers: ["v2-terenuri-hit", "v2-cladiri-fill"],
      });
      if (feats.length === 0) {
        onFeatureClick(null);
        return;
      }
      const f = feats[0];
      if (!f?.properties) {
        onFeatureClick(null);
        return;
      }
      const p = f.properties as Record<string, unknown>;
      const sourceLayer =
        (f as unknown as { sourceLayer?: string }).sourceLayer ?? "";
      const layerId =
        sourceLayer === "gis_cladiri" ? "CLADIRI_ACTIVE" : "TERENURI_ACTIVE";

      const id = typeof p.id === "string" ? p.id : "";
      const objectId =
        typeof p.object_id === "number"
          ? String(p.object_id)
          : typeof p.object_id === "string"
            ? p.object_id
            : "";
      const siruta = String(p.siruta ?? "");
      const cadastralRef = String(p.cadastral_ref ?? "");

      // Need at least cadastralRef + siruta to identify the parcel.
      if (!cadastralRef || !siruta) {
        console.warn("[v2-click] tile props missing siruta/cadastral_ref:", p);
        onFeatureClick(null);
        return;
      }

      onFeatureClick({
        id, // may be empty when tile lacks uuid; panel falls back to parcel/tech
        objectId,
        siruta,
        cadastralRef,
        layerId,
        areaValue:
          typeof p.area_value === "number" ? (p.area_value as number) : undefined,
      });
    };
    map.on("click", onClick);
    map.getCanvas().style.cursor = "default";

    return () => {
      map.off("click", onClick);
      map.remove();
      mapRef.current = null;
    };
  }, [basemap, addGisLayers, onFeatureClick]);

  useImperativeHandle(
    ref,
    () => ({
      flyTo: (center, zoom) => {
        mapRef.current?.flyTo({
          center,
          zoom: zoom ?? mapRef.current.getZoom(),
          essential: true,
        });
      },
      getMap: () => mapRef.current,
    }),
    [],
  );

  return (
    <div
      ref={containerRef}
      className={cn("h-full w-full", className)}
      data-ready={ready}
    />
  );
});
