"use client";

import { useRef, useEffect, useState, useCallback, useImperativeHandle, forwardRef } from "react";
import maplibregl from "maplibre-gl";
import { Protocol as PmtilesProtocol } from "pmtiles";
import { cn } from "@/shared/lib/utils";

/* Ensure MapLibre CSS is loaded — static import fails with next/dynamic + standalone */
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 globally (once) for pmtiles:// source URLs */
if (typeof window !== "undefined") {
  const pmtilesProto = new PmtilesProtocol();
  maplibregl.addProtocol("pmtiles", pmtilesProto.tile);
}

import type { BasemapId, ClickedFeature, LayerVisibility, SelectedFeature } from "../types";

/* ------------------------------------------------------------------ */
/*  Selection type (re-exported for convenience)                       */
/* ------------------------------------------------------------------ */

export type SelectionType = "off" | "click" | "rect" | "freehand";

/* ------------------------------------------------------------------ */
/*  Constants                                                          */
/* ------------------------------------------------------------------ */

const DEFAULT_MARTIN_URL = process.env.NEXT_PUBLIC_MARTIN_URL || "/tiles";
const DEFAULT_PMTILES_URL = process.env.NEXT_PUBLIC_PMTILES_URL || "";
const DEFAULT_CENTER: [number, number] = [23.8, 46.1];
const DEFAULT_ZOOM = 7;

const SOURCES = {
  uatsZ0: "gis_uats_z0",
  uatsZ5: "gis_uats_z5",
  uatsZ8: "gis_uats_z8",
  uatsZ12: "gis_uats_z12",
  terenuri: "gis_terenuri",
  cladiri: "gis_cladiri",
  administrativ: "gis_administrativ",
} as const;

const LAYER_IDS = {
  uatsZ0Line: "l-uats-z0-line",
  uatsZ5Fill: "l-uats-z5-fill",
  uatsZ5Line: "l-uats-z5-line",
  uatsZ8Fill: "l-uats-z8-fill",
  uatsZ8Line: "l-uats-z8-line",
  uatsZ8Label: "l-uats-z8-label",
  uatsZ12Fill: "l-uats-z12-fill",
  uatsZ12Line: "l-uats-z12-line",
  uatsZ12Label: "l-uats-z12-label",
  adminLineOuter: "l-admin-line-outer",
  adminLineInner: "l-admin-line-inner",
  terenuriFill: "l-terenuri-fill",
  terenuriLine: "l-terenuri-line",
  terenuriLabel: "l-terenuri-label",
  cladiriFill: "l-cladiri-fill",
  cladiriLine: "l-cladiri-line",
  cladiriLabel: "l-cladiri-label",
  selectionFill: "l-selection-fill",
  selectionLine: "l-selection-line",
  drawPolygonFill: "l-draw-polygon-fill",
  drawPolygonLine: "l-draw-polygon-line",
} as const;

const DRAW_SOURCE = "draw-polygon";

/* ---- Basemap definitions ---- */
type BasemapDef =
  | { type: "style"; url: string; maxzoom?: number }
  | { 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,
  },
  orto: {
    type: "raster",
    tiles: ["/api/eterra/tiles/orto?z={z}&x={x}&y={y}"],
    attribution: '&copy; <a href="https://ancpi.ro">ANCPI</a> Ortofoto 2024',
    tileSize: 512,
    maxzoom: 19,
  },
};

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

/* ------------------------------------------------------------------ */
/*  Point-in-polygon (ray casting)                                     */
/* ------------------------------------------------------------------ */

function pointInPolygon(point: [number, number], polygon: [number, number][]): boolean {
  let inside = false;
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    const pi = polygon[i];
    const pj = polygon[j];
    if (!pi || !pj) continue;
    const xi = pi[0], yi = pi[1];
    const xj = pj[0], yj = pj[1];
    if ((yi > point[1]) !== (yj > point[1]) && point[0] < ((xj - xi) * (point[1] - yi)) / (yj - yi) + xi) {
      inside = !inside;
    }
  }
  return inside;
}

/* ------------------------------------------------------------------ */
/*  Empty GeoJSON constant                                             */
/* ------------------------------------------------------------------ */

const EMPTY_GEOJSON: GeoJSON.FeatureCollection = {
  type: "FeatureCollection",
  features: [],
};

/* ------------------------------------------------------------------ */
/*  Props & Handle                                                     */
/* ------------------------------------------------------------------ */

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

type MapViewerProps = {
  center?: [number, number];
  zoom?: number;
  martinUrl?: string;
  className?: string;
  basemap?: BasemapId;
  selectionType?: SelectionType;
  onFeatureClick?: (feature: ClickedFeature) => void;
  onSelectionChange?: (features: SelectedFeature[]) => void;
  layerVisibility?: LayerVisibility;
};

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

export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
  function MapViewer(
    {
      center, zoom, martinUrl, className,
      basemap = "liberty",
      selectionType = "off",
      onFeatureClick, onSelectionChange, layerVisibility,
    },
    ref
  ) {
    const containerRef = useRef<HTMLDivElement>(null);
    const mapRef = useRef<maplibregl.Map | null>(null);
    const selectedRef = useRef<Map<string, SelectedFeature>>(new Map());
    const selectionTypeRef = useRef<SelectionType>(selectionType);
    const [mapReady, setMapReady] = useState(false);

    // Persist view state across basemap switches
    const viewStateRef = useRef({ center: center ?? DEFAULT_CENTER, zoom: zoom ?? DEFAULT_ZOOM });

    // --- Rectangle drawing state ---
    const rectStartRef = useRef<{ x: number; y: number } | null>(null);
    const rectOverlayRef = useRef<HTMLDivElement | null>(null);
    const rectDrawingRef = useRef(false);

    // --- Freehand polygon drawing state ---
    const freehandPointsRef = useRef<[number, number][]>([]);

    selectionTypeRef.current = selectionType;

    const resolvedMartinUrl = (() => {
      const raw = martinUrl ?? DEFAULT_MARTIN_URL;
      if (raw.startsWith("http")) return raw;
      if (typeof window !== "undefined") return `${window.location.origin}${raw}`;
      return raw;
    })();

    /* ---- Selection helpers ---- */
    const updateSelectionFilter = useCallback(() => {
      const map = mapRef.current;
      if (!map) return;
      const ids = Array.from(selectedRef.current.keys());
      const filter: maplibregl.FilterSpecification =
        ids.length > 0
          ? ["in", ["to-string", ["get", "object_id"]], ["literal", ids]]
          : ["==", "object_id", "__NONE__"];
      try {
        if (map.getLayer(LAYER_IDS.selectionFill)) map.setFilter(LAYER_IDS.selectionFill, filter);
        if (map.getLayer(LAYER_IDS.selectionLine)) map.setFilter(LAYER_IDS.selectionLine, filter);
      } catch { /* noop */ }
    }, []);

    const clearSelection = useCallback(() => {
      selectedRef.current.clear();
      updateSelectionFilter();
      onSelectionChange?.([]);
    }, [updateSelectionFilter, onSelectionChange]);

    /* ---- Clear draw state helper ---- */
    const clearDrawState = useCallback(() => {
      // Clear rect state
      rectStartRef.current = null;
      rectDrawingRef.current = false;
      if (rectOverlayRef.current) {
        rectOverlayRef.current.remove();
        rectOverlayRef.current = null;
      }
      // Clear freehand state
      freehandPointsRef.current = [];
      // Clear draw polygon source on map
      const map = mapRef.current;
      if (map) {
        try {
          const src = map.getSource(DRAW_SOURCE) as maplibregl.GeoJSONSource | undefined;
          if (src) src.setData(EMPTY_GEOJSON);
        } catch { /* noop */ }
        // Re-enable drag pan in case it was disabled
        try { map.dragPan.enable(); } catch { /* noop */ }
      }
    }, []);

    /* ---- Update draw polygon source ---- */
    const updateDrawPolygon = useCallback((points: [number, number][]) => {
      const map = mapRef.current;
      if (!map) return;
      try {
        const src = map.getSource(DRAW_SOURCE) as maplibregl.GeoJSONSource | undefined;
        if (!src) return;
        if (points.length < 2) {
          src.setData(EMPTY_GEOJSON);
          return;
        }
        // Show as polygon if 3+ points, otherwise as line
        const coords = [...points];
        if (points.length >= 3) {
          // Close the ring for display
          const first = points[0];
          if (first) coords.push(first);
        }
        const features: GeoJSON.Feature[] = [];
        if (points.length >= 3) {
          features.push({
            type: "Feature",
            properties: {},
            geometry: { type: "Polygon", coordinates: [coords] },
          });
        }
        // Always draw the line
        features.push({
          type: "Feature",
          properties: {},
          geometry: { type: "LineString", coordinates: coords },
        });
        src.setData({ type: "FeatureCollection", features });
      } catch { /* noop */ }
    }, []);

    /* ---- Add terenuri features from a pixel bbox to selection ---- */
    const addFeaturesFromBbox = useCallback((bbox: [maplibregl.PointLike, maplibregl.PointLike]) => {
      const map = mapRef.current;
      if (!map) return;
      try {
        const features = map.queryRenderedFeatures(bbox);
        for (const f of features) {
          const sl = f.sourceLayer ?? f.source ?? "";
          if (sl !== SOURCES.terenuri) continue;
          const props = (f.properties ?? {}) as Record<string, unknown>;
          const objectId = String(props.object_id ?? "");
          if (!objectId) continue;
          selectedRef.current.set(objectId, { id: objectId, sourceLayer: sl, properties: props });
        }
        updateSelectionFilter();
        onSelectionChange?.(Array.from(selectedRef.current.values()));
      } catch { /* noop */ }
    }, [updateSelectionFilter, onSelectionChange]);

    /* ---- Imperative handle ---- */
    useImperativeHandle(ref, () => ({
      getMap: () => mapRef.current,
      setLayerVisibility: (vis: LayerVisibility) => applyLayerVisibility(vis),
      flyTo: (c: [number, number], z?: number) => {
        mapRef.current?.flyTo({ center: c, zoom: z ?? 14, duration: 1500 });
      },
      clearSelection,
    }));

    /* ---- Apply layer visibility ---- */
    const applyLayerVisibility = useCallback((vis: LayerVisibility) => {
      const map = mapRef.current;
      if (!map) return;
      const mapping: Record<string, string[]> = {
        uats: [
          LAYER_IDS.uatsZ0Line,
          LAYER_IDS.uatsZ5Fill, LAYER_IDS.uatsZ5Line,
          LAYER_IDS.uatsZ8Fill, LAYER_IDS.uatsZ8Line, LAYER_IDS.uatsZ8Label,
          LAYER_IDS.uatsZ12Fill, LAYER_IDS.uatsZ12Line, LAYER_IDS.uatsZ12Label,
        ],
        administrativ: [LAYER_IDS.adminLineOuter, LAYER_IDS.adminLineInner],
        terenuri: [LAYER_IDS.terenuriFill, LAYER_IDS.terenuriLine, LAYER_IDS.terenuriLabel, "l-terenuri-pm-fill", "l-terenuri-pm-line", "l-terenuri-pm-label"],
        cladiri: [LAYER_IDS.cladiriFill, LAYER_IDS.cladiriLine, LAYER_IDS.cladiriLabel, "l-cladiri-pm-fill", "l-cladiri-pm-line"],
      };
      for (const [group, layerIds] of Object.entries(mapping)) {
        const visible = vis[group] !== false;
        for (const lid of layerIds) {
          try { map.setLayoutProperty(lid, "visibility", visible ? "visible" : "none"); } catch { /* noop */ }
        }
      }
    }, []);

    useEffect(() => {
      if (mapReady && layerVisibility) applyLayerVisibility(layerVisibility);
    }, [mapReady, layerVisibility, applyLayerVisibility]);

    /* ---- Clean up draw state when selectionType changes ---- */
    useEffect(() => {
      clearDrawState();
    }, [selectionType, clearDrawState]);

    /* ---- Map initialization (recreates on basemap change) ---- */
    useEffect(() => {
      if (!containerRef.current) return;

      const basemapDef = BASEMAPS[basemap];
      const map = new maplibregl.Map({
        container: containerRef.current,
        style: buildStyle(basemapDef),
        center: viewStateRef.current.center,
        zoom: viewStateRef.current.zoom,
        maxZoom: basemapDef.maxzoom ?? 20,
      });

      mapRef.current = map;

      // Save view state on every move (for basemap switch preservation)
      map.on("moveend", () => {
        viewStateRef.current = {
          center: map.getCenter().toArray() as [number, number],
          zoom: map.getZoom(),
        };
      });

      map.addControl(new maplibregl.NavigationControl(), "top-right");
      map.addControl(new maplibregl.ScaleControl({ unit: "metric" }), "bottom-left");

      /* ---- Add Martin sources + layers on load ---- */
      map.on("load", () => {
        const m = resolvedMartinUrl;

        // Hide OpenFreeMap's built-in boundary/admin layers
        for (const layer of map.getStyle().layers) {
          const id = layer.id;
          // Match common OpenMapTiles boundary layer naming patterns
          if (/boundar|admin|border(?!.*water)|oneway|arrow/i.test(id)) {
            try { map.setLayoutProperty(layer.id, "visibility", "none"); } catch { /* noop */ }
          }
          // Also hide by source-layer (more reliable)
          const sl = ("source-layer" in layer && typeof layer["source-layer"] === "string") ? layer["source-layer"] : "";
          if (sl === "boundary" || sl === "admin") {
            try { map.setLayoutProperty(layer.id, "visibility", "none"); } catch { /* noop */ }
          }
        }

        // === UAT sources: PMTiles (if configured) or Martin fallback ===
        const pmtilesUrl = DEFAULT_PMTILES_URL;
        const usePmtiles = !!pmtilesUrl;

        if (usePmtiles) {
          // Single PMTiles source contains all UAT + administrativ layers (z0-z14)
          const PM_SRC = "overview-pmtiles";
          map.addSource(PM_SRC, { type: "vector", url: `pmtiles://${pmtilesUrl}` });

          // z0-5: lines only
          map.addLayer({ id: LAYER_IDS.uatsZ0Line, type: "line", source: PM_SRC, "source-layer": SOURCES.uatsZ0, maxzoom: 5,
            paint: { "line-color": "#7c3aed", "line-width": 0.3 } });

          // z5-8
          map.addLayer({ id: LAYER_IDS.uatsZ5Line, type: "line", source: PM_SRC, "source-layer": SOURCES.uatsZ5, minzoom: 5, maxzoom: 8,
            paint: { "line-color": "#7c3aed", "line-width": 0.6 } });

          // z8-12
          map.addLayer({ id: LAYER_IDS.uatsZ8Line, type: "line", source: PM_SRC, "source-layer": SOURCES.uatsZ8, minzoom: 8, maxzoom: 12,
            paint: { "line-color": "#7c3aed", "line-width": 1 } });
          map.addLayer({ id: LAYER_IDS.uatsZ8Label, type: "symbol", source: PM_SRC, "source-layer": SOURCES.uatsZ8, minzoom: 9, maxzoom: 12,
            layout: { "text-field": ["coalesce", ["get", "name"], ""], "text-font": ["Noto Sans Regular"], "text-size": 10, "text-anchor": "center", "text-allow-overlap": false },
            paint: { "text-color": "#5b21b6", "text-halo-color": "#fff", "text-halo-width": 1.5 } });

          // z12+: full detail from PMTiles
          map.addLayer({ id: LAYER_IDS.uatsZ12Line, type: "line", source: PM_SRC, "source-layer": SOURCES.uatsZ12, minzoom: 12,
            paint: { "line-color": "#7c3aed", "line-width": 2 } });
          map.addLayer({ id: LAYER_IDS.uatsZ12Label, type: "symbol", source: PM_SRC, "source-layer": SOURCES.uatsZ12, minzoom: 12,
            layout: { "text-field": ["coalesce", ["get", "name"], ""], "text-font": ["Noto Sans Regular"], "text-size": 13, "text-anchor": "center", "text-allow-overlap": false },
            paint: { "text-color": "#5b21b6", "text-halo-color": "#fff", "text-halo-width": 1.5 } });

          // Intravilan from PMTiles
          map.addLayer({ id: LAYER_IDS.adminLineOuter, type: "line", source: PM_SRC, "source-layer": SOURCES.administrativ, minzoom: 13,
            paint: { "line-color": "#000000", "line-width": 3 } });
          map.addLayer({ id: LAYER_IDS.adminLineInner, type: "line", source: PM_SRC, "source-layer": SOURCES.administrativ, minzoom: 13,
            paint: { "line-color": "#f97316", "line-width": 1.5 } });
        } else {
          // Fallback: Martin tile sources (existing behavior)

          // z0-5: very coarse — lines only
          map.addSource(SOURCES.uatsZ0, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ0}/{z}/{x}/{y}`], minzoom: 0, maxzoom: 5 });
          map.addLayer({ id: LAYER_IDS.uatsZ0Line, type: "line", source: SOURCES.uatsZ0, "source-layer": SOURCES.uatsZ0, maxzoom: 5,
            paint: { "line-color": "#7c3aed", "line-width": 0.3 } });

          // z5-8: coarse
          map.addSource(SOURCES.uatsZ5, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ5}/{z}/{x}/{y}`], minzoom: 5, maxzoom: 8 });
          map.addLayer({ id: LAYER_IDS.uatsZ5Line, type: "line", source: SOURCES.uatsZ5, "source-layer": SOURCES.uatsZ5, minzoom: 5, maxzoom: 8,
            paint: { "line-color": "#7c3aed", "line-width": 0.6 } });

          // z8-12: moderate
          map.addSource(SOURCES.uatsZ8, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ8}/{z}/{x}/{y}`], minzoom: 8, maxzoom: 12 });
          map.addLayer({ id: LAYER_IDS.uatsZ8Line, type: "line", source: SOURCES.uatsZ8, "source-layer": SOURCES.uatsZ8, minzoom: 8, maxzoom: 12,
            paint: { "line-color": "#7c3aed", "line-width": 1 } });
          map.addLayer({ id: LAYER_IDS.uatsZ8Label, type: "symbol", source: SOURCES.uatsZ8, "source-layer": SOURCES.uatsZ8, minzoom: 9, maxzoom: 12,
            layout: { "text-field": ["coalesce", ["get", "name"], ""], "text-font": ["Noto Sans Regular"], "text-size": 10, "text-anchor": "center", "text-allow-overlap": false },
            paint: { "text-color": "#5b21b6", "text-halo-color": "#fff", "text-halo-width": 1.5 } });

          // z12+: full detail (no simplification)
          map.addSource(SOURCES.uatsZ12, { type: "vector", tiles: [`${m}/${SOURCES.uatsZ12}/{z}/{x}/{y}`], minzoom: 12, maxzoom: 16 });
          map.addLayer({ id: LAYER_IDS.uatsZ12Line, type: "line", source: SOURCES.uatsZ12, "source-layer": SOURCES.uatsZ12, minzoom: 12,
            paint: { "line-color": "#7c3aed", "line-width": 2 } });
          map.addLayer({ id: LAYER_IDS.uatsZ12Label, type: "symbol", source: SOURCES.uatsZ12, "source-layer": SOURCES.uatsZ12, minzoom: 12,
            layout: { "text-field": ["coalesce", ["get", "name"], ""], "text-font": ["Noto Sans Regular"], "text-size": 13, "text-anchor": "center", "text-allow-overlap": false },
            paint: { "text-color": "#5b21b6", "text-halo-color": "#fff", "text-halo-width": 1.5 } });

          // Intravilan — double line (black outer + orange inner), no fill, z13+
          map.addSource(SOURCES.administrativ, { type: "vector", tiles: [`${m}/${SOURCES.administrativ}/{z}/{x}/{y}`], minzoom: 10, maxzoom: 16 });
          map.addLayer({ id: LAYER_IDS.adminLineOuter, type: "line", source: SOURCES.administrativ, "source-layer": SOURCES.administrativ, minzoom: 13,
            paint: { "line-color": "#000000", "line-width": 3 } });
          map.addLayer({ id: LAYER_IDS.adminLineInner, type: "line", source: SOURCES.administrativ, "source-layer": SOURCES.administrativ, minzoom: 13,
            paint: { "line-color": "#f97316", "line-width": 1.5 } });
        }

        // === Terenuri (parcels) ===
        if (usePmtiles) {
          // PMTiles serves ALL zoom levels (z13-z18) — zero PostGIS load
          map.addLayer({ id: "l-terenuri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13,
            paint: { "fill-color": "#22c55e", "fill-opacity": 0.15 } });
          map.addLayer({ id: "l-terenuri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13,
            paint: { "line-color": "#15803d", "line-width": 0.8 } });
          map.addLayer({ id: "l-terenuri-pm-label", type: "symbol", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, 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": "#166534", "text-halo-color": "#fff", "text-halo-width": 1 } });
          // Martin source registered but unused (selection uses PMTiles source now)
          // Kept as fallback reference — no tile requests since no layers target it
          map.addSource(SOURCES.terenuri, { type: "vector", tiles: [`${m}/${SOURCES.terenuri}/{z}/{x}/{y}`], minzoom: 17, maxzoom: 18 });
        } else {
          map.addSource(SOURCES.terenuri, { type: "vector", tiles: [`${m}/${SOURCES.terenuri}/{z}/{x}/{y}`], minzoom: 10, maxzoom: 18 });
          map.addLayer({ id: LAYER_IDS.terenuriFill, type: "fill", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: 13,
            paint: { "fill-color": "#22c55e", "fill-opacity": 0.15 } });
          map.addLayer({ id: LAYER_IDS.terenuriLine, type: "line", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: 13,
            paint: { "line-color": "#15803d", "line-width": 0.8 } });
          map.addLayer({ id: LAYER_IDS.terenuriLabel, type: "symbol", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, 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": "#166534", "text-halo-color": "#fff", "text-halo-width": 1 } });
        }

        // === Cladiri (buildings) ===
        if (usePmtiles) {
          // PMTiles serves ALL zoom levels (z14-z18) — zero PostGIS load
          map.addLayer({ id: "l-cladiri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14,
            paint: { "fill-color": "#3b82f6", "fill-opacity": 0.5 } });
          map.addLayer({ id: "l-cladiri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14,
            paint: { "line-color": "#1e3a5f", "line-width": 0.6 } });
          map.addSource(SOURCES.cladiri, { type: "vector", tiles: [`${m}/${SOURCES.cladiri}/{z}/{x}/{y}`], minzoom: 17, maxzoom: 18 });
        } else {
          map.addSource(SOURCES.cladiri, { type: "vector", tiles: [`${m}/${SOURCES.cladiri}/{z}/{x}/{y}`], minzoom: 12, maxzoom: 18 });
          map.addLayer({ id: LAYER_IDS.cladiriFill, type: "fill", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: 14,
            paint: { "fill-color": "#3b82f6", "fill-opacity": 0.5 } });
          map.addLayer({ id: LAYER_IDS.cladiriLine, type: "line", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: 14,
            paint: { "line-color": "#1e3a5f", "line-width": 0.6 } });
        }
        // Building body labels — extract suffix after last dash (e.g. "291479-C1" → "C1")
        map.addLayer({ id: LAYER_IDS.cladiriLabel, type: "symbol",
          source: usePmtiles ? "overview-pmtiles" : SOURCES.cladiri,
          "source-layer": SOURCES.cladiri, minzoom: 16,
          layout: {
            "text-field": [
              "case",
              ["has", "cadastral_ref"],
              ["let", "ref", ["get", "cadastral_ref"],
                ["let", "dashIdx", ["index-of", "-", ["var", "ref"]],
                  ["case",
                    [">=", ["var", "dashIdx"], 0],
                    ["slice", ["var", "ref"], ["+", ["var", "dashIdx"], 1]],
                    ["var", "ref"],
                  ],
                ],
              ],
              "",
            ],
            "text-font": ["Noto Sans Regular"],
            "text-size": 9, "text-anchor": "center", "text-allow-overlap": false,
            "text-max-width": 6,
          },
          paint: { "text-color": "#1e3a5f", "text-halo-color": "#fff", "text-halo-width": 1 } });

        // === Selection highlight ===
        // Use PMTiles source when available (has data at z13+), Martin only has z17+
        const selectionSrc = usePmtiles ? "overview-pmtiles" : SOURCES.terenuri;
        map.addLayer({ id: LAYER_IDS.selectionFill, type: "fill", source: selectionSrc, "source-layer": SOURCES.terenuri, minzoom: 13,
          filter: ["==", "object_id", "__NONE__"],
          paint: { "fill-color": "#f59e0b", "fill-opacity": 0.5 } });
        map.addLayer({ id: LAYER_IDS.selectionLine, type: "line", source: selectionSrc, "source-layer": SOURCES.terenuri, minzoom: 13,
          filter: ["==", "object_id", "__NONE__"],
          paint: { "line-color": "#d97706", "line-width": 2.5 } });

        // === Draw polygon source + layers (for freehand) ===
        map.addSource(DRAW_SOURCE, { type: "geojson", data: EMPTY_GEOJSON });
        map.addLayer({
          id: LAYER_IDS.drawPolygonFill, type: "fill", source: DRAW_SOURCE,
          filter: ["==", "$type", "Polygon"],
          paint: { "fill-color": "#f59e0b", "fill-opacity": 0.2 },
        });
        map.addLayer({
          id: LAYER_IDS.drawPolygonLine, type: "line", source: DRAW_SOURCE,
          paint: { "line-color": "#f59e0b", "line-width": 2, "line-dasharray": [3, 2] },
        });

        // HIDE ALL data layers immediately after creation
        const allLayerIds = [
          ...Object.values(LAYER_IDS).filter(id => !id.includes("draw") && !id.includes("selection")),
        ];
        for (const lid of allLayerIds) {
          try { map.setLayoutProperty(lid, "visibility", "none"); } catch { /* noop */ }
        }
        // Then show only the ones that should be visible
        if (layerVisibility) applyLayerVisibility(layerVisibility);
        setMapReady(true);
      });

      /* ---- Click handler — NO popup, only callback ---- */
      // Include both Martin and PMTiles fill layers — filter() skips non-existent ones
      const clickableLayers = [
        LAYER_IDS.terenuriFill, LAYER_IDS.cladiriFill,
        "l-terenuri-pm-fill", "l-cladiri-pm-fill",
      ];

      map.on("click", (e) => {
        const mode = selectionTypeRef.current;

        // --- Freehand mode: clicks add points ---
        if (mode === "freehand") {
          const lngLat: [number, number] = [e.lngLat.lng, e.lngLat.lat];
          freehandPointsRef.current.push(lngLat);
          updateDrawPolygon(freehandPointsRef.current);
          return;
        }

        // --- Rect mode: clicks are handled by mousedown/up, ignore normal clicks ---
        if (mode === "rect") return;

        const features = map.queryRenderedFeatures(e.point, {
          layers: clickableLayers.filter((l) => { try { return !!map.getLayer(l); } catch { return false; } }),
        });

        if (features.length === 0) {
          // Clear highlight when clicking empty space
          try {
            map.setFilter(LAYER_IDS.selectionFill, ["==", "object_id", "__NONE__"]);
            map.setFilter(LAYER_IDS.selectionLine, ["==", "object_id", "__NONE__"]);
          } catch { /* noop */ }
          onFeatureClick?.(null as unknown as ClickedFeature); // close panel
          return;
        }

        const first = features[0];
        if (!first) return;

        const props = (first.properties ?? {}) as Record<string, unknown>;
        const sourceLayer = first.sourceLayer ?? first.source ?? "";

        // Click selection mode
        if (mode === "click" && sourceLayer === SOURCES.terenuri) {
          const objectId = String(props.object_id ?? "");
          if (!objectId) return;
          if (selectedRef.current.has(objectId)) {
            selectedRef.current.delete(objectId);
          } else {
            selectedRef.current.set(objectId, { id: objectId, sourceLayer, properties: props });
          }
          updateSelectionFilter();
          onSelectionChange?.(Array.from(selectedRef.current.values()));
          return;
        }

        // Feature click — notify parent (no popup) — only when off
        if (mode === "off") {
          // Highlight clicked parcel with selection layer
          const objectId = String(props.object_id ?? "");
          if (objectId && sourceLayer === SOURCES.terenuri) {
            try {
              map.setFilter(LAYER_IDS.selectionFill, ["==", "object_id", objectId]);
              map.setFilter(LAYER_IDS.selectionLine, ["==", "object_id", objectId]);
            } catch { /* noop */ }
          }
          onFeatureClick?.({
            layerId: first.layer?.id ?? "",
            sourceLayer,
            properties: props,
            coordinates: [e.lngLat.lng, e.lngLat.lat],
          });
        }
      });

      /* ---- Double-click handler for freehand polygon completion ---- */
      map.on("dblclick", (e) => {
        const mode = selectionTypeRef.current;
        if (mode !== "freehand") return;

        // Prevent default double-click zoom
        e.preventDefault();

        const points = freehandPointsRef.current;
        if (points.length < 3) {
          // Not enough points, clear
          freehandPointsRef.current = [];
          updateDrawPolygon([]);
          return;
        }

        // Close polygon — compute pixel bbox of all points
        let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
        for (const pt of points) {
          const px = map.project(pt);
          if (px.x < minX) minX = px.x;
          if (px.y < minY) minY = px.y;
          if (px.x > maxX) maxX = px.x;
          if (px.y > maxY) maxY = px.y;
        }

        // Query all rendered features in the bbox
        try {
          const allFeatures = map.queryRenderedFeatures(
            [[minX, minY], [maxX, maxY]] as [maplibregl.PointLike, maplibregl.PointLike]
          );

          // For each terenuri feature, check if center is inside the drawn polygon
          for (const f of allFeatures) {
            const sl = f.sourceLayer ?? f.source ?? "";
            if (sl !== SOURCES.terenuri) continue;
            const props = (f.properties ?? {}) as Record<string, unknown>;
            const objectId = String(props.object_id ?? "");
            if (!objectId) continue;

            // Get feature center in lng/lat
            // Use the feature's geometry bbox center via queryRenderedFeatures pixel point
            // Since we're dealing with rendered features, use the feature geometry
            const geom = f.geometry;
            let centerLngLat: [number, number] | null = null;

            if (geom.type === "Polygon" || geom.type === "MultiPolygon") {
              // Compute centroid from coordinates
              const coords = geom.type === "Polygon" ? geom.coordinates[0] : geom.coordinates[0]?.[0];
              if (coords && coords.length > 0) {
                let cx = 0, cy = 0;
                for (const c of coords) {
                  const coord = c as [number, number];
                  cx += coord[0];
                  cy += coord[1];
                }
                centerLngLat = [cx / coords.length, cy / coords.length];
              }
            } else if (geom.type === "Point") {
              centerLngLat = geom.coordinates as [number, number];
            }

            if (!centerLngLat) continue;

            if (pointInPolygon(centerLngLat, points)) {
              selectedRef.current.set(objectId, { id: objectId, sourceLayer: sl, properties: props });
            }
          }

          updateSelectionFilter();
          onSelectionChange?.(Array.from(selectedRef.current.values()));
        } catch { /* noop */ }

        // Clear draw polygon
        freehandPointsRef.current = [];
        updateDrawPolygon([]);
      });

      /* ---- Rectangle selection: mousedown/mousemove/mouseup on canvas ---- */
      const canvas = map.getCanvas();

      const onRectMouseDown = (e: MouseEvent) => {
        if (selectionTypeRef.current !== "rect") return;
        // Only respond to left-click (button 0)
        if (e.button !== 0) return;

        rectStartRef.current = { x: e.offsetX, y: e.offsetY };
        rectDrawingRef.current = true;

        // Disable map drag pan while drawing rectangle
        map.dragPan.disable();

        // Create overlay div
        const container = containerRef.current;
        if (!container) return;
        const overlay = document.createElement("div");
        overlay.style.position = "absolute";
        overlay.style.pointerEvents = "none";
        overlay.style.backgroundColor = "rgba(245, 158, 11, 0.2)";
        overlay.style.border = "2px solid rgba(245, 158, 11, 0.8)";
        overlay.style.left = `${e.offsetX}px`;
        overlay.style.top = `${e.offsetY}px`;
        overlay.style.width = "0px";
        overlay.style.height = "0px";
        overlay.style.zIndex = "10";
        container.appendChild(overlay);
        rectOverlayRef.current = overlay;
      };

      const onRectMouseMove = (e: MouseEvent) => {
        if (!rectDrawingRef.current || !rectStartRef.current || !rectOverlayRef.current) return;
        const start = rectStartRef.current;
        const overlay = rectOverlayRef.current;
        const x = Math.min(start.x, e.offsetX);
        const y = Math.min(start.y, e.offsetY);
        const w = Math.abs(e.offsetX - start.x);
        const h = Math.abs(e.offsetY - start.y);
        overlay.style.left = `${x}px`;
        overlay.style.top = `${y}px`;
        overlay.style.width = `${w}px`;
        overlay.style.height = `${h}px`;
      };

      const onRectMouseUp = (e: MouseEvent) => {
        if (!rectDrawingRef.current || !rectStartRef.current) return;
        rectDrawingRef.current = false;

        const start = rectStartRef.current;
        rectStartRef.current = null;

        // Re-enable drag pan
        map.dragPan.enable();

        // Remove overlay
        if (rectOverlayRef.current) {
          rectOverlayRef.current.remove();
          rectOverlayRef.current = null;
        }

        // Compute pixel bbox
        const x1 = Math.min(start.x, e.offsetX);
        const y1 = Math.min(start.y, e.offsetY);
        const x2 = Math.max(start.x, e.offsetX);
        const y2 = Math.max(start.y, e.offsetY);

        // Minimum size check (avoid accidental tiny rectangles)
        if (Math.abs(x2 - x1) < 5 && Math.abs(y2 - y1) < 5) return;

        addFeaturesFromBbox([[x1, y1], [x2, y2]]);
      };

      canvas.addEventListener("mousedown", onRectMouseDown);
      canvas.addEventListener("mousemove", onRectMouseMove);
      canvas.addEventListener("mouseup", onRectMouseUp);

      /* ---- ESC key exits selection mode ---- */
      const onKeyDown = (e: KeyboardEvent) => {
        if (e.key === "Escape" && selectionTypeRef.current !== "off") {
          onFeatureClick?.(null as unknown as ClickedFeature);
          clearDrawState();
          // Notify parent to turn off selection
          onSelectionChange?.([]);
        }
      };
      document.addEventListener("keydown", onKeyDown);

      /* ---- Right-click exits selection / cancels draw ---- */
      map.on("contextmenu", (e) => {
        if (selectionTypeRef.current !== "off") {
          e.preventDefault();
          clearDrawState();
        }
      });

      /* ---- Cursor change ---- */
      for (const lid of clickableLayers) {
        map.on("mouseenter", lid, () => { map.getCanvas().style.cursor = "pointer"; });
        map.on("mouseleave", lid, () => { map.getCanvas().style.cursor = ""; });
      }

      /* ---- Cleanup ---- */
      return () => {
        document.removeEventListener("keydown", onKeyDown);
        canvas.removeEventListener("mousedown", onRectMouseDown);
        canvas.removeEventListener("mousemove", onRectMouseMove);
        canvas.removeEventListener("mouseup", onRectMouseUp);
        // Clean up any lingering overlay
        if (rectOverlayRef.current) {
          rectOverlayRef.current.remove();
          rectOverlayRef.current = null;
        }
        map.remove();
        mapRef.current = null;
        setMapReady(false);
      };
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [resolvedMartinUrl, basemap]);

    /* ---- Disable interactions when in drawing modes ---- */
    useEffect(() => {
      const map = mapRef.current;
      if (!map) return;
      if (selectionType === "freehand") {
        map.doubleClickZoom.disable();
        map.dragPan.disable();
      } else if (selectionType === "rect") {
        // rect handles dragPan itself in mousedown/mouseup
      } else {
        map.doubleClickZoom.enable();
        map.dragPan.enable();
      }
    }, [selectionType, mapReady]);

    return (
      <div className={cn("absolute inset-0", className)}>
        <div ref={containerRef} className="relative w-full h-full" />
        {!mapReady && (
          <div className="absolute inset-0 flex items-center justify-center bg-muted/50">
            <p className="text-sm text-muted-foreground">Se incarca harta...</p>
          </div>
        )}
      </div>
    );
  }
);
