// Mapbox-backed Lagos map with real admin boundaries (GeoJSON overlays).
const MAPBOX_TOKEN = "pk.eyJ1IjoiamFkczYxMSIsImEiOiJjbW9rajl0bWQwNmpuMnFzYWZ1cHg3ZG5nIn0.h9r38ftbVfrAaz0lAmlEBg";

function MapCanvas({ focus, layers = {}, subject, mapStyle, pitch = 0, bearing = 0 }) {
  const mapEl = React.useRef(null);
  const mapRef = React.useRef(null);
  const [tick, setTick] = React.useState(0);

  React.useEffect(() => {
    let map, ro, rzTimer, cancelled = false;

    const addBoundaries = async (m) => {
      try {
        const [sen, lines, pts] = await Promise.all([
          fetch("data/lagos_senatorial.geojson").then(r => r.json()),
          fetch("data/lagos_adminlines.geojson").then(r => r.json()),
          fetch("data/lagos_adminpoints.geojson").then(r => r.json()),
        ]);

        // 1) Senatorial district polygons (coloured by district)
        m.addSource("lagos-senatorial", { type: "geojson", data: sen });
        m.addLayer({
          id: "sen-fill",
          type: "fill",
          source: "lagos-senatorial",
          paint: {
            "fill-color": [
              "match", ["get", "sendist_en"],
              "Lagos West",    "#c49a3c",
              "Lagos Central", "#1aa088",
              "Lagos East",    "#56647a",
              "#aab3c2"
            ],
            "fill-opacity": 0.18,
          },
          layout: { visibility: layers.senatorial ? "visible" : "none" },
        });
        m.addLayer({
          id: "sen-line",
          type: "line",
          source: "lagos-senatorial",
          paint: { "line-color": "#1a2332", "line-width": 1.5, "line-opacity": 0.55, "line-dasharray": [2, 2] },
          layout: { visibility: layers.senatorial ? "visible" : "none" },
        });

        // 2) LGA admin lines (adm_level == 2 is LGA, 1 is state)
        m.addSource("lagos-adminlines", { type: "geojson", data: lines });
        m.addLayer({
          id: "adm-line-lga",
          type: "line",
          source: "lagos-adminlines",
          filter: ["==", ["get", "adm_level"], 2],
          paint: { "line-color": "#0a0f15", "line-width": 1.1, "line-opacity": 0.45 },
          layout: { visibility: layers.lgaLines !== false ? "visible" : "none" },
        });
        m.addLayer({
          id: "adm-line-state",
          type: "line",
          source: "lagos-adminlines",
          filter: ["==", ["get", "adm_level"], 1],
          paint: { "line-color": "#0a0f15", "line-width": 2, "line-opacity": 0.8 },
          layout: { visibility: layers.lgaLines !== false ? "visible" : "none" },
        });

        // 3) LGA name labels (admin_level == 2)
        m.addSource("lagos-points", { type: "geojson", data: pts });
        m.addLayer({
          id: "lga-labels",
          type: "symbol",
          source: "lagos-points",
          filter: ["==", ["get", "admin_level"], 2],
          layout: {
            "text-field": ["get", "name"],
            "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
            "text-size": 11,
            "text-anchor": "center",
            "text-letter-spacing": 0.04,
            "text-allow-overlap": false,
            "visibility": layers.labels !== false ? "visible" : "none",
          },
          paint: {
            "text-color": "#1a2332",
            "text-halo-color": "rgba(255,255,255,0.9)",
            "text-halo-width": 1.6,
          },
        });
      } catch (e) { console.warn("boundaries load failed", e); }
    };

    const tryInit = () => {
      if (cancelled) return;
      if (!window.mapboxgl) { requestAnimationFrame(tryInit); return; }
      const el = mapEl.current;
      if (!el) { requestAnimationFrame(tryInit); return; }
      const w = el.clientWidth, h = el.clientHeight;
      if (w < 10 || h < 10) { requestAnimationFrame(tryInit); return; }

      const isSat = mapStyle === "satellite";
      window.mapboxgl.accessToken = MAPBOX_TOKEN;
      map = new window.mapboxgl.Map({
        container: el,
        style: isSat
          ? "mapbox://styles/mapbox/satellite-streets-v12"
          : "mapbox://styles/mapbox/light-v11",
        center: [3.45, 6.55],
        zoom: isSat ? 10.5 : 10.3,
        pitch: pitch || (isSat ? 30 : 0),
        bearing: bearing || 0,
        attributionControl: false,
        pitchWithRotate: isSat,
        dragRotate: isSat,
      });
      mapRef.current = map;
      const bump = () => setTick(t => t + 1);

      map.on("load", () => {
        if (!isSat) {
          try { map.setPaintProperty("water", "fill-color", "#a9c7c0"); } catch(e) {}
        }
        if (isSat) {
          try {
            map.addSource("mapbox-dem", {
              type: "raster-dem",
              url: "mapbox://mapbox.mapbox-terrain-dem-v1",
              tileSize: 512, maxzoom: 14,
            });
            map.setTerrain({ source: "mapbox-dem", exaggeration: 1.5 });
            map.addLayer({
              id: "3d-buildings",
              source: "composite",
              "source-layer": "building",
              filter: ["==", "extrude", "true"],
              type: "fill-extrusion",
              minzoom: 12,
              paint: {
                "fill-extrusion-color": "#e8722a",
                "fill-extrusion-height": ["interpolate", ["linear"], ["zoom"], 14, 0, 16, ["get", "height"]],
                "fill-extrusion-base":   ["interpolate", ["linear"], ["zoom"], 14, 0, 16, ["get", "min_height"]],
                "fill-extrusion-opacity": 0.55,
              },
            });
          } catch(e) { console.warn("3D buildings failed", e); }
        }
        map.resize();
        map.triggerRepaint();
        if (!isSat) addBoundaries(map);
        bump();
      });
      map.on("move", bump);
      map.on("moveend", bump);

      let lastW = w, lastH = h;
      ro = new ResizeObserver(entries => {
        const r = entries[0].contentRect;
        if (Math.abs(r.width - lastW) < 2 && Math.abs(r.height - lastH) < 2) return;
        lastW = r.width; lastH = r.height;
        clearTimeout(rzTimer);
        rzTimer = setTimeout(() => { try { map.resize(); map.triggerRepaint(); bump(); } catch(e) {} }, 80);
      });
      ro.observe(el);
    };
    requestAnimationFrame(tryInit);

    return () => {
      cancelled = true;
      if (ro) ro.disconnect();
      clearTimeout(rzTimer);
      if (map) map.remove();
      mapRef.current = null;
    };
  }, []);

  // React to layer toggle changes
  React.useEffect(() => {
    const m = mapRef.current;
    if (!m || !m.isStyleLoaded || !m.isStyleLoaded()) return;
    const set = (id, v) => { if (m.getLayer(id)) m.setLayoutProperty(id, "visibility", v ? "visible" : "none"); };
    set("sen-fill",     !!layers.senatorial);
    set("sen-line",     !!layers.senatorial);
    set("adm-line-lga", layers.lgaLines !== false);
    set("adm-line-state", layers.lgaLines !== false);
    set("lga-labels",   layers.labels !== false);
  }, [layers.senatorial, layers.lgaLines, layers.labels, tick]);

  const map = mapRef.current;
  const w = mapEl.current?.clientWidth || 0;
  const h = mapEl.current?.clientHeight || 0;
  const ready = map && w > 0 && h > 0;
  const proj = ready ? (lng, lat) => { const p = map.project([lng, lat]); return [p.x, p.y]; } : null;

  const color = { building:"#c49a3c", completed:"#1aa088", planned:"#56647a", stalled:"#b4413a" };

  return (
    <div style={{ position:"absolute", inset:0 }}>
      <div ref={mapEl} style={{ position:"absolute", inset:0 }}/>
      {proj && (
        <svg width={w} height={h}
             style={{ position:"absolute", inset:0, pointerEvents:"none" }}
             viewBox={`0 0 ${w} ${h}`}>
          {layers.pipeline !== false && window.PIPELINE.map(p => {
            const [x,y] = proj(p.lng, p.lat);
            return (
              <g key={p.id} transform={`translate(${x},${y})`}>
                <circle r="14" fill={color[p.status]} fillOpacity="0.18"/>
                <circle r="6.5" fill={color[p.status]} stroke="#fff" strokeWidth="2"/>
              </g>
            );
          })}
          {subject && (() => {
            const [x,y] = proj(subject.lng, subject.lat);
            return (
              <g transform={`translate(${x},${y})`}>
                <circle r="26" fill="none" stroke="#0f1720" strokeWidth="2" strokeDasharray="4 4">
                  <animate attributeName="r" values="18;30;18" dur="2.4s" repeatCount="indefinite"/>
                </circle>
                <circle r="5" fill="#0f1720"/>
              </g>
            );
          })()}
        </svg>
      )}
    </div>
  );
}

window.MapCanvas = MapCanvas;
