const { MapLegend, STATUS } = window.TersusDesignSystem_b3db99;

const cssVar = (name, fallback) =>
  (getComputedStyle(document.documentElement).getPropertyValue(name) || "").trim() || fallback;

function pinHtml(status, selected) {
  const s = STATUS[status] || STATUS.neu;
  const hq = status === "standort";
  const d = hq ? 30 : selected ? 28 : 22;
  const glyph = hq ? '<span style="width:14px;height:14px;background:#fff;-webkit-mask:url(https://unpkg.com/lucide-static@0.441.0/icons/building-2.svg) no-repeat center/contain;mask:url(https://unpkg.com/lucide-static@0.441.0/icons/building-2.svg) no-repeat center/contain"></span>' : "";
  return '<span style="display:flex;align-items:center;justify-content:center;width:'+d+'px;height:'+d+'px;border-radius:'+(hq?"6px":"999px")+';background:'+s.color+';border:1.5px solid '+(status==="neu"?cssVar("--pin-rim","#4A4A43"):"rgba(0,0,0,.35)")+';box-shadow:'+(selected?"0 0 0 3px #CCDD00":"0 1px 3px rgba(26,26,24,.35)")+';transition:width 180ms,height 180ms">'+glyph+"</span>";
}

function pinIcon(status, selected) {
  const d = status === "standort" ? 30 : selected ? 28 : 22;
  return L.divIcon({ className: "tersus-pin", html: pinHtml(status, selected), iconSize: [d, d], iconAnchor: [d/2, d/2] });
}

/* Gruppen-Pin: Anzahl der zusammengefassten Karteikarten. Neutral in Ink, damit die
   Statusfarben den einzelnen Pins vorbehalten bleiben. */
function clusterIcon(cluster) {
  const n = cluster.getChildCount();
  const d = n < 10 ? 30 : n < 100 ? 36 : 44;
  return L.divIcon({ className: "tersus-cluster", html: "<span>" + n + "</span>", iconSize: [d, d] });
}

const LEGEND_BREAKPOINT = 760;
const START_CENTER = [51.47, 6.98];
const START_ZOOM = 10;
/* Startausschnitt: Ruhrgebiet (RVR-Gebiet). Einzelne Adressen ausserhalb, etwa
   Konzernzentralen in Berlin, sollen den Ausschnitt nicht aufziehen. */
const RUHR_BOUNDS = [[51.30, 6.55], [51.72, 7.72]];

function ausschnittSetzen(map, el) {
  if (!el || !el.clientWidth || !el.clientHeight) return;
  /* Breite Karte: Legende steht als Block unten links, dafuer Freiraum links.
     Schmale Karte: Legende laeuft als Streifen ueber die Unterkante. */
  const breit = el.clientWidth >= LEGEND_BREAKPOINT;
  const padL = breit ? Math.min(262, Math.round(el.clientWidth * 0.28)) : 20;
  const padB = breit ? Math.min(180, Math.round(el.clientHeight * 0.26)) : 76;
  map.fitBounds(L.latLngBounds(RUHR_BOUNDS), {
    paddingTopLeft: [padL, 24],
    paddingBottomRight: [28, padB],
    maxZoom: 12,
    animate: false,
  });
}

function MapPanel({ objekte, hq, selectedId, onSelect, counts, sidebarOffen }) {
  const ref = React.useRef(null);
  const mapRef = React.useRef(null);
  const clusterRef = React.useRef(null);
  const markersRef = React.useRef({});
  const onSelectRef = React.useRef(onSelect);
  const selectedRef = React.useRef(selectedId);
  onSelectRef.current = onSelect;

  const [bereit, setBereit] = React.useState(false);
  const [breiteKarte, setBreiteKarte] = React.useState(true);

  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let ro = null, raf = 0;

    const map = L.map(el, { zoomControl: false, attributionControl: true })
      .setView(START_CENTER, START_ZOOM, { animate: false });
    /* Helles Theme: Standard-OSM-Tiles, per CSS leicht entsaettigt und aufgehellt
       (.leaflet-tile in index.html). Der CARTO-Layer aus dem Briefing verlangt einen API-Key. */
    L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>-Mitwirkende · Darstellung entsaettigt',
      maxZoom: 19,
    }).addTo(map);
    L.control.zoom({ position: "topright" }).addTo(map);
    map.on("dragstart zoomstart", () => { map._tersusTouched = true; });

    const cluster = L.markerClusterGroup({
      chunkedLoading: true,
      showCoverageOnHover: false,
      maxClusterRadius: 44,
      disableClusteringAtZoom: 14,
      spiderfyOnMaxZoom: true,
      iconCreateFunction: clusterIcon,
    });
    map.addLayer(cluster);
    clusterRef.current = cluster;

    /* Zentrale nie gruppieren, sie ist Orientierungspunkt. */
    L.marker([hq.lat, hq.lng], { icon: pinIcon("standort", false), title: hq.name + " — " + STATUS.standort.label, zIndexOffset: 500 }).addTo(map);

    mapRef.current = map;
    setBereit(true);

    const nachmessen = () => {
      setBreiteKarte(el.clientWidth >= LEGEND_BREAKPOINT);
      map.invalidateSize();
      if (!map._tersusTouched) ausschnittSetzen(map, el);
    };
    nachmessen();
    raf = requestAnimationFrame(() => map.whenReady(nachmessen));
    if (typeof ResizeObserver !== "undefined") {
      ro = new ResizeObserver(nachmessen);
      ro.observe(el);
    }
    window.addEventListener("resize", nachmessen);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", nachmessen);
      if (ro) ro.disconnect();
      markersRef.current = {};
      if (mapRef.current) { mapRef.current.remove(); mapRef.current = null; }
    };
  }, []);

  React.useEffect(() => {
    const map = mapRef.current; if (!map) return;
    const t = setTimeout(() => {
      map.invalidateSize();
      if (!map._tersusTouched) ausschnittSetzen(map, ref.current);
    }, 0);
    return () => clearTimeout(t);
  }, [sidebarOffen]);

  /* Pins abgleichen statt neu aufbauen: neue anlegen, gefilterte entfernen,
     bei Statuswechsel nur das Icon tauschen. */
  React.useEffect(() => {
    const cluster = clusterRef.current; if (!cluster || !bereit) return;
    const markers = markersRef.current;
    const sichtbar = new Set();
    const neu = [];
    objekte.forEach(o => {
      if (o.lat == null || o.lng == null) return;
      sichtbar.add(o.id);
      const m = markers[o.id];
      if (m) {
        if (m._tersusStatus !== o.status) {
          m._tersusStatus = o.status;
          m.setIcon(pinIcon(o.status, o.id === selectedRef.current));
        }
        if (!cluster.hasLayer(m)) neu.push(m);
        return;
      }
      const marker = L.marker([o.lat, o.lng], {
        icon: pinIcon(o.status, o.id === selectedRef.current),
        title: o.name + " — " + (STATUS[o.status] || {}).label,
        keyboard: true,
      });
      marker._tersusStatus = o.status;
      marker.on("click", () => onSelectRef.current(o.id));
      markers[o.id] = marker;
      neu.push(marker);
    });
    const weg = Object.keys(markers).filter(id => !sichtbar.has(id) && cluster.hasLayer(markers[id])).map(id => markers[id]);
    if (weg.length) cluster.removeLayers(weg);
    if (neu.length) cluster.addLayers(neu);
  }, [objekte, bereit]);

  /* Auswahl: alten Pin zuruecksetzen, neuen hervorheben und ins Bild holen. */
  React.useEffect(() => {
    const markers = markersRef.current;
    const alt = selectedRef.current;
    selectedRef.current = selectedId;
    if (alt && markers[alt]) { markers[alt].setIcon(pinIcon(markers[alt]._tersusStatus, false)); markers[alt].setZIndexOffset(0); }
    const m = selectedId && markers[selectedId];
    if (!m || !clusterRef.current || !clusterRef.current.hasLayer(m)) return;
    m.setIcon(pinIcon(m._tersusStatus, true));
    m.setZIndexOffset(1000);
    clusterRef.current.zoomToShowLayer(m, () => {
      const map = mapRef.current;
      if (map && !map.getBounds().pad(-0.1).contains(m.getLatLng())) map.panTo(m.getLatLng());
    });
  }, [selectedId, bereit]);

  return (
    <div style={{position:"relative",flex:1,minWidth:0,background:"var(--surface-page)"}}>
      <div ref={ref} style={{position:"absolute",inset:0}} />
      <div style={{position:"absolute",left:12,right:breiteKarte?"auto":12,bottom:26,zIndex:500,width:breiteKarte?238:"auto"}}>
        <MapLegend counts={counts} layout={breiteKarte?"stack":"inline"} />
      </div>
    </div>
  );
}

Object.assign(window, { MapPanel });
