/* MapPicker.jsx — Leaflet map.
   Modes:
     pick  : single editable marker, click to set, onChange({lat,lng})
     view  : render props.markers, click marker -> onSelect(id)
*/
const { useEffect, useRef } = React;

const TILES = {
  standard:  { url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png", attr: "© CARTO · OSM", sub: "abc" },
  satellite: { url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", attr: "© Esri, Maxar, Earthstar Geographics" },
  terrain:   { url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png", attr: "© OpenTopoMap", sub: "abc" },
  minimal:   { url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png", attr: "© CARTO · OSM", sub: "abc" },
};

function statusColor(s) {
  return s === "new" ? "var(--st-new)" : s === "review" ? "var(--st-review)" : "var(--st-resolved)";
}

function pinIcon() {
  const c = "var(--accent)";
  return L.divIcon({
    className: "",
    html: `<div style="position:relative;transform:translate(-50%,-100%);">
      <div style="width:30px;height:30px;border-radius:50% 50% 50% 0;transform:rotate(-45deg);
        background:${c};border:2.5px solid #fff;box-shadow:0 4px 12px rgba(0,0,0,.3);"></div>
      <div style="position:absolute;left:50%;top:9px;width:9px;height:9px;border-radius:50%;
        background:#fff;transform:translate(-50%,0);"></div>
    </div>`,
    iconSize: [30, 30], iconAnchor: [0, 0],
  });
}

function dotIcon(status, active) {
  const c = statusColor(status);
  const size = active ? 22 : 15;
  return L.divIcon({
    className: "",
    html: `<div style="transform:translate(-50%,-50%);width:${size}px;height:${size}px;border-radius:50%;
      background:${c};border:${active ? 3 : 2}px solid #fff;
      box-shadow:0 2px 8px rgba(0,0,0,.35);${active ? "outline:3px solid color-mix(in oklab, " + c + " 40%, transparent);" : ""}"></div>`,
    iconSize: [size, size], iconAnchor: [0, 0],
  });
}

function MapPicker({ mode = "pick", center, mapStyle = "standard", value, onChange,
                     markers = [], selectedId, onSelect, t, locateRef, showGeofence = false, areas = [] }) {
  const elRef = useRef(null);
  const mapRef = useRef(null);
  const tileRef = useRef(null);
  const markerRef = useRef(null);
  const layerRef = useRef(null);
  const areasLayerRef = useRef(null);
  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;
  const onSelectRef = useRef(onSelect);
  onSelectRef.current = onSelect;

  useEffect(() => {
    const map = L.map(elRef.current, {
      center: center || [47.4985, 9.6365],
      zoom: 13, zoomControl: true, scrollWheelZoom: true, attributionControl: true,
    });
    mapRef.current = map;
    map.zoomControl.setPosition("bottomright");

    if (showGeofence && window.MELD.geofence) {
      L.polygon(window.MELD.geofence, {
        color: "#4B7054",
        weight: 2,
        dashArray: "7, 5",
        fillOpacity: 0.07,
        fillColor: "#4B7054",
        interactive: false,
      }).addTo(map);
    }

    areasLayerRef.current = L.layerGroup().addTo(map);

    if (mode === "pick") {
      map.on("click", (e) => onChangeRef.current && onChangeRef.current({ lat: e.latlng.lat, lng: e.latlng.lng }));
    }
    setTimeout(() => map.invalidateSize(), 60);
    const ro = new ResizeObserver(() => { if (mapRef.current) mapRef.current.invalidateSize(); });
    ro.observe(elRef.current);

    if (locateRef) {
      locateRef.current = () => {
        if (!navigator.geolocation) return fallbackLocate(map);
        navigator.geolocation.getCurrentPosition(
          (pos) => {
            const ll = { lat: pos.coords.latitude, lng: pos.coords.longitude };
            map.setView([ll.lat, ll.lng], 15);
            onChangeRef.current && onChangeRef.current(ll);
          },
          () => fallbackLocate(map),
          { timeout: 6000 }
        );
      };
    }

    function fallbackLocate(map) {
      const c = center || [47.4985, 9.6365];
      map.setView(c, 14);
    }

    return () => { ro.disconnect(); map.remove(); mapRef.current = null; };
  }, []);

  useEffect(() => {
    const map = mapRef.current; if (!map) return;
    const conf = TILES[mapStyle] || TILES.standard;
    if (tileRef.current) map.removeLayer(tileRef.current);
    const opts = { attribution: conf.attr, maxZoom: 19 };
    if (conf.sub) opts.subdomains = conf.sub;
    tileRef.current = L.tileLayer(conf.url, opts).addTo(map);
  }, [mapStyle]);

  useEffect(() => {
    const layer = areasLayerRef.current; if (!layer) return;
    layer.clearLayers();
    const geoLayers = [];
    areas.forEach(a => {
      try {
        const gj = typeof a.geojson === "string" ? JSON.parse(a.geojson) : a.geojson;
        const l = L.geoJSON(gj, { style: { color: "#3388ff", fillColor: "#3388ff", fillOpacity: 0.22, weight: 2 }, interactive: false });
        l.addTo(layer);
        geoLayers.push(l);
      } catch (e) {}
    });
    if (geoLayers.length && mapRef.current) {
      const grp = L.featureGroup(geoLayers.flatMap(l => l.getLayers()));
      if (grp.getLayers().length) mapRef.current.fitBounds(grp.getBounds(), { padding: [30, 30] });
    }
  }, [areas]);

  useEffect(() => {
    if (mode !== "pick") return;
    const map = mapRef.current; if (!map) return;
    if (value && value.lat != null) {
      if (!markerRef.current) {
        markerRef.current = L.marker([value.lat, value.lng], { icon: pinIcon() }).addTo(map);
      } else {
        markerRef.current.setLatLng([value.lat, value.lng]);
      }
    } else if (markerRef.current) {
      map.removeLayer(markerRef.current); markerRef.current = null;
    }
  }, [value && value.lat, value && value.lng]);

  useEffect(() => {
    if (mode !== "view") return;
    const map = mapRef.current; if (!map) return;
    if (layerRef.current) map.removeLayer(layerRef.current);
    const grp = L.layerGroup();
    const validMarkers = markers.filter(m => m.ll && m.ll[0] != null && m.ll[1] != null);
    validMarkers.forEach((m) => {
      const mk = L.marker(m.ll, { icon: dotIcon(m.status, m.id === selectedId), zIndexOffset: m.id === selectedId ? 1000 : 0 });
      mk.on("click", () => onSelectRef.current && onSelectRef.current(m.id));
      grp.addLayer(mk);
    });
    grp.addTo(map);
    layerRef.current = grp;

    if (selectedId) {
      const sel = validMarkers.find(m => m.id === selectedId);
      if (sel) map.panTo(sel.ll, { animate: true });
    }
  }, [markers, selectedId]);

  return <div ref={elRef} style={{ position: "absolute", inset: 0 }}></div>;
}

window.MapPicker = MapPicker;
