/* eslint-disable no-undef */
// Live Leaflet map: real satellite basemap + NASA GIBS layers + IDW sensor heatmap + markers.
// Plus a live weather / soil / air panel fed by Open-Meteo, OpenWeather, Ambee.

const { useState: lmUseState, useEffect: lmUseEffect, useRef: lmUseRef, useMemo: lmUseMemo } = React;

// ============ Live weather / soil / air panel ============
function LiveEnvPanel({ lat, lng, seed = 1, compact = false }) {
  const [bundle, setBundle] = lmUseState(null);
  const [loading, setLoading] = lmUseState(true);
  const [updated, setUpdated] = lmUseState(null);

  const load = () => {
    setLoading(true);
    getLiveBundle(lat, lng, seed).then((b) => {
      setBundle(b); setLoading(false); setUpdated(new Date());
    });
  };
  lmUseEffect(() => { load(); /* eslint-disable-next-line */ }, [lat, lng]);

  if (loading && !bundle) {
    return (
      <div className="card" style={{ padding: 24, textAlign: "center" }}>
        <div className="pulse-dot" style={{ margin: "0 auto 10px" }} />
        <div className="dim" style={{ fontSize: 12 }}>Fetching live weather, soil & air data…</div>
      </div>
    );
  }
  const { weather, soil, air, forecast } = bundle;

  const aqiColor = air.aqi <= 50 ? "var(--green)" : air.aqi <= 100 ? "var(--amber)" : "var(--rose)";

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {/* Current weather */}
      <div className="card">
        <div className="card-hd">
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 500, whiteSpace: "nowrap" }}>Live conditions</div>
            <div className="dim" style={{ fontSize: 11, marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{weather.desc ? cap(weather.desc) : wmoLabel(weather.code)}</div>
          </div>
          <span className={"tag " + (weather.live ? "ok" : "warn")} style={{ fontSize: 10 }}>
            <span className="pulse-dot" style={{ width: 6, height: 6, background: weather.live ? "var(--green)" : "var(--amber)" }} />
            {weather.live ? weather.source : "estimated"}
          </span>
        </div>
        <div className="card-bd" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
            <Metric label="Air temp" value={fmt(weather.temp, 1)} unit="°C" color="var(--amber)" />
            <Metric label="Humidity" value={Math.round(weather.humidity)} unit="%" color="var(--cyan)" />
            <Metric label="Wind" value={fmt(weather.wind, 1)} unit="km/h" color="var(--green)" />
            <Metric label="Precip" value={fmt(weather.precip, 1)} unit="mm" color="var(--violet)" />
          </div>
          <div className="h-rule" />
          <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
            <Metric label="Feels like" value={fmt(weather.feels, 1)} unit="°C" small />
            <Metric label="Pressure" value={Math.round(weather.pressure)} unit="hPa" small />
            <Metric label="UV index" value={fmt(weather.uv, 1)} unit="" small color={weather.uv > 6 ? "var(--rose)" : weather.uv > 3 ? "var(--amber)" : "var(--green)"} />
            <Metric label="Cloud" value={Math.round(weather.clouds)} unit="%" small />
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, paddingTop: 2 }}>
            <span className="dim">Wind {weather.windDir}{weather.gust ? ` · gust ${fmt(weather.gust, 0)} km/h` : ""}</span>
            <span className="dim">☀ {weather.sunrise ? new Date(weather.sunrise).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "—"} · {weather.sunset ? new Date(weather.sunset).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "—"}</span>
          </div>
        </div>
      </div>

      {/* Pollen & fire risk */}
      <div className="card">
        <div className="card-hd">
          <div style={{ fontSize: 13, fontWeight: 500 }}>Pollen & fire risk</div>
          <span className={"tag " + (bundle.pollen.live || bundle.fire.live ? "ok" : "warn")} style={{ fontSize: 10 }}>{bundle.pollen.live || bundle.fire.live ? "Ambee" : "estimated"}</span>
        </div>
        <div className="card-bd" style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 12 }}>
          <PollenItem label="Tree pollen" risk={bundle.pollen.tree} count={bundle.pollen.treeCount} />
          <PollenItem label="Grass pollen" risk={bundle.pollen.grass} count={bundle.pollen.grassCount} />
          <PollenItem label="Weed pollen" risk={bundle.pollen.weed} />
          <div>
            <div className="faint" style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: "0.05em" }}>Wildfire</div>
            <div style={{ display: "flex", alignItems: "baseline", gap: 5, marginTop: 4 }}>
              <span style={{ fontSize: 13, fontWeight: 600, color: bundle.fire.risk === "Elevated" ? "var(--rose)" : "var(--green)" }}>{bundle.fire.risk}</span>
            </div>
            <div className="faint" style={{ fontSize: 10, marginTop: 2 }}>{bundle.fire.count} active · nearest {bundle.fire.nearest}</div>
          </div>
        </div>
      </div>

      {/* Soil profile */}
      <div className="card">
        <div className="card-hd">
          <div style={{ fontSize: 13, fontWeight: 500 }}>Soil profile by depth</div>
          <span className={"tag " + (soil.live ? "ok" : "warn")} style={{ fontSize: 10 }}>{soil.live ? soil.source : "estimated"}</span>
        </div>
        <div className="card-bd" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {soil.layers.map((l, i) => {
            const moisturePct = l.moisture != null ? (l.moisture <= 1 ? l.moisture * 100 : l.moisture) : null;
            return (
              <div key={i} style={{ display: "grid", gridTemplateColumns: "54px 1fr 70px", gap: 10, alignItems: "center" }}>
                <span className="mono dim" style={{ fontSize: 11 }}>{l.depth}</span>
                <div style={{ display: "flex", flexDirection: "column", gap: 3 }}>
                  <Bar value={moisturePct ?? 0} max={60} color="var(--cyan)" h={5} />
                </div>
                <div style={{ textAlign: "right", display: "flex", flexDirection: "column" }}>
                  <span className="mono tnum" style={{ fontSize: 11 }}>{moisturePct != null ? moisturePct.toFixed(0) + "%" : "—"}</span>
                  <span className="mono faint" style={{ fontSize: 10 }}>{l.temp != null ? fmt(l.temp, 1) + "°C" : ""}</span>
                </div>
              </div>
            );
          })}
          {soil.ambee && (
            <div className="dim" style={{ fontSize: 11, paddingTop: 6, borderTop: "1px solid var(--border-faint)" }}>
              Ambee: surface soil {fmt(soil.ambee.soil_temperature, 1)}°C · moisture {fmt(soil.ambee.soil_moisture, 2)}
            </div>
          )}
        </div>
      </div>

      {/* Air quality */}
      <div className="card">
        <div className="card-hd">
          <div style={{ fontSize: 13, fontWeight: 500 }}>Air quality</div>
          <span className={"tag " + (air.live ? "ok" : "warn")} style={{ fontSize: 10 }}>{air.live ? air.source : "estimated"}</span>
        </div>
        <div className="card-bd">
          <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 14 }}>
            <div style={{ width: 56, height: 56, borderRadius: 12, background: `color-mix(in oklch, ${aqiColor} 18%, var(--surface-2))`, display: "grid", placeItems: "center", border: `1px solid ${aqiColor}` }}>
              <div style={{ textAlign: "center" }}>
                <div className="mono tnum" style={{ fontSize: 20, fontWeight: 700, color: aqiColor, lineHeight: 1 }}>{Math.round(air.aqi)}</div>
              </div>
            </div>
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>US AQI · {air.aqi <= 50 ? "Good" : air.aqi <= 100 ? "Moderate" : "Unhealthy"}</div>
              <div className="dim" style={{ fontSize: 11, marginTop: 2 }}>Cross-checked against on-farm AirWatch nodes</div>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10 }}>
            <Metric label="PM2.5" value={fmt(air.pm25, 1)} unit="µg/m³" small />
            <Metric label="PM10" value={fmt(air.pm10, 1)} unit="µg/m³" small />
            <Metric label="O₃" value={fmt(air.o3, 0)} unit="µg/m³" small />
            <Metric label="NO₂" value={fmt(air.no2, 1)} unit="µg/m³" small />
            <Metric label="NH₃" value={fmt(air.nh3, 1)} unit="µg/m³" small />
            <Metric label="CO" value={fmt(air.co, 0)} unit="µg/m³" small />
          </div>
        </div>
      </div>

      {/* 7-day forecast */}
      <div className="card">
        <div className="card-hd"><div style={{ fontSize: 13, fontWeight: 500 }}>7-day forecast</div><span className="dim" style={{ fontSize: 11 }}>Open-Meteo</span></div>
        <div className="card-bd" style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 6 }}>
          {forecast.map((d, i) => (
            <div key={i} style={{ textAlign: "center", padding: "8px 4px", background: "var(--bg-elev)", borderRadius: 8 }}>
              <div className="dim" style={{ fontSize: 10 }}>{new Date(d.date).toLocaleDateString(undefined, { weekday: "short" })}</div>
              <div className="mono tnum" style={{ fontSize: 14, fontWeight: 600, marginTop: 4 }}>{Math.round(d.max)}°</div>
              <div className="mono faint" style={{ fontSize: 10 }}>{Math.round(d.min)}°</div>
              {d.precip > 0.2 && <div className="mono" style={{ fontSize: 9, color: "var(--cyan)", marginTop: 2 }}>{d.precip.toFixed(0)}mm</div>}
            </div>
          ))}
        </div>
      </div>

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "0 4px" }}>
        <span className="faint" style={{ fontSize: 10 }}>Updated {updated ? updated.toLocaleTimeString() : "—"} · {lat.toFixed(3)}, {lng.toFixed(3)}</span>
        <button className="btn ghost" onClick={load} style={{ fontSize: 11, padding: "4px 8px" }}><Icon name="refresh" size={12} /> Refresh</button>
      </div>
    </div>
  );
}

function Metric({ label, value, unit, color = "var(--text)", small }) {
  return (
    <div>
      <div className="faint" style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: "0.05em" }}>{label}</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 3, marginTop: 2 }}>
        <span className="mono tnum" style={{ fontSize: small ? 15 : 20, fontWeight: 600, color }}>{value}</span>
        <span className="dim mono" style={{ fontSize: 10 }}>{unit}</span>
      </div>
    </div>
  );
}
function fmt(v, d = 1) { return v == null || isNaN(v) ? "—" : (+v).toFixed(d); }
function cap(s) { return s ? s.charAt(0).toUpperCase() + s.slice(1) : s; }
function PollenItem({ label, risk, count }) {
  const c = risk === "High" ? "var(--rose)" : risk === "Moderate" ? "var(--amber)" : "var(--green)";
  return (
    <div>
      <div className="faint" style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: "0.05em" }}>{label}</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 5, marginTop: 4 }}>
        <span style={{ fontSize: 13, fontWeight: 600, color: c }}>{risk}</span>
        {count != null && <span className="faint mono" style={{ fontSize: 10 }}>{count}/m³</span>}
      </div>
    </div>
  );
}

// ============ CSA Earth-observation panel ============
function CSAPanel() {
  const [data, setData] = lmUseState(null);
  lmUseEffect(() => { getCSAData("soil moisture radarsat").then(setData); }, []);
  return (
    <div className="card">
      <div className="card-hd">
        <div>
          <div style={{ fontSize: 13, fontWeight: 500 }}>Canadian Space Agency · Earth observation</div>
          <div className="dim" style={{ fontSize: 11, marginTop: 2 }}>RADARSAT SAR & soil-moisture datasets</div>
        </div>
        <span className={"tag " + (data?.live ? "ok" : "warn")} style={{ fontSize: 10 }}>{data ? (data.live ? "live · CSA API" : "catalog") : "…"}</span>
      </div>
      <div className="card-bd" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {!data && <div className="dim" style={{ fontSize: 12 }}>Querying CSA open data…</div>}
        {data && data.datasets.slice(0, 5).map((d, i) => (
          <a key={i} href={d.url || "https://donnees-data.asc-csa.gc.ca"} target="_blank" rel="noreferrer"
            style={{ textDecoration: "none", color: "inherit", display: "block", padding: 10, background: "var(--bg-elev)", borderRadius: 8, border: "1px solid var(--border-faint)" }}>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 8, alignItems: "baseline" }}>
              <div style={{ fontSize: 12.5, fontWeight: 500, color: "var(--text)" }}>{d.title}</div>
              <span className="tag info" style={{ fontSize: 9, flexShrink: 0 }}>{d.tag}</span>
            </div>
            <div className="dim" style={{ fontSize: 11, marginTop: 4, lineHeight: 1.45 }}>{d.note}</div>
            <div className="faint" style={{ fontSize: 10, marginTop: 4 }}>{d.org}</div>
          </a>
        ))}
        <div className="faint" style={{ fontSize: 10 }}>Source: donnees-data.asc-csa.gc.ca · {data?.count ?? "—"} datasets</div>
      </div>
    </div>
  );
}

// ============ Leaflet live field map ============
function LiveFieldMap({ farm, sensors, height = 560 }) {
  const mapRef = lmUseRef(null);
  const mapEl = lmUseRef(null);
  const heatOverlayRef = lmUseRef(null);
  const markerLayerRef = lmUseRef(null);
  const gibsLayerRef = lmUseRef(null);
  const cdseOverlayRef = lmUseRef(null);
  const fieldLayerRef = lmUseRef(null);

  const [metric, setMetric] = lmUseState("ndvi");
  const [opacity, setOpacity] = lmUseState(0.72);
  const [showHeat, setShowHeat] = lmUseState(true);
  const [showMarkers, setShowMarkers] = lmUseState(true);
  const [showFields, setShowFields] = lmUseState(true);
  const [gibs, setGibs] = lmUseState("none");
  const [cdseStatus, setCdseStatus] = lmUseState(null); // null | loading | live | offline
  const [ready, setReady] = lmUseState(false);

  const { FAMILIES } = window.AGB_DATA;

  const fieldGeo = lmUseMemo(() => farmFieldGeoJSON(farm, sensors), [farm, sensors]);

  // sensor points with metric values
  const points = lmUseMemo(() => sensors.map((s) => ({
    lat: s.lat, lng: s.lng, value: sensorMetricValue(s, metric), sensor: s,
  })), [sensors, metric]);

  const bounds = lmUseMemo(() => {
    const lats = sensors.map((s) => s.lat), lngs = sensors.map((s) => s.lng);
    const pad = 0.004;
    return {
      minLat: Math.min(...lats) - pad, maxLat: Math.max(...lats) + pad,
      minLng: Math.min(...lngs) - pad, maxLng: Math.max(...lngs) + pad,
    };
  }, [sensors]);

  // init map
  lmUseEffect(() => {
    if (!window.L || mapRef.current || !mapEl.current) return;
    const L = window.L;
    const map = L.map(mapEl.current, { zoomControl: true, attributionControl: true, scrollWheelZoom: true });
    mapRef.current = map;
    // Esri satellite basemap (real imagery, no key)
    L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", {
      maxZoom: 19, attribution: "Esri World Imagery",
    }).addTo(map);
    // Labels overlay
    L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}", {
      maxZoom: 19, opacity: 0.5,
    }).addTo(map);

    map.fitBounds([[bounds.minLat, bounds.minLng], [bounds.maxLat, bounds.maxLng]], { padding: [20, 20] });
    markerLayerRef.current = L.layerGroup().addTo(map);
    setReady(true);
    setTimeout(() => map.invalidateSize(), 200);
    return () => { map.remove(); mapRef.current = null; };
  }, []);

  // heatmap overlay
  lmUseEffect(() => {
    if (!ready || !mapRef.current) return;
    const L = window.L;
    if (heatOverlayRef.current) { mapRef.current.removeLayer(heatOverlayRef.current); heatOverlayRef.current = null; }
    if (showHeat) {
      const url = buildHeatmapCanvas(points, bounds, metric);
      const ov = L.imageOverlay(url, [[bounds.minLat, bounds.minLng], [bounds.maxLat, bounds.maxLng]], { opacity, interactive: false });
      ov.addTo(mapRef.current);
      heatOverlayRef.current = ov;
    }
  }, [ready, points, metric, showHeat, bounds]);

  // opacity live
  lmUseEffect(() => { if (heatOverlayRef.current) heatOverlayRef.current.setOpacity(opacity); }, [opacity]);

  // markers
  lmUseEffect(() => {
    if (!ready || !markerLayerRef.current) return;
    const L = window.L;
    markerLayerRef.current.clearLayers();
    if (!showMarkers) return;
    points.forEach((p) => {
      const color = colorVar(FAMILIES[p.sensor.family].color);
      const m = L.circleMarker([p.lat, p.lng], {
        radius: 6, color: "#0b0f14", weight: 1.5, fillColor: color, fillOpacity: 1,
      });
      m.bindPopup(
        `<div style="font-family:ui-sans-serif;min-width:150px">
          <div style="font-weight:600;font-size:13px">${p.sensor.name}</div>
          <div style="color:#888;font-size:11px;margin:2px 0 6px">${p.sensor.family} · ${p.sensor.id}</div>
          <div style="display:flex;justify-content:space-between;font-size:12px"><span style="color:#888">${FIELD_METRICS[metric].label}</span><b>${p.value}${FIELD_METRICS[metric].unit}</b></div>
          <div style="display:flex;justify-content:space-between;font-size:12px"><span style="color:#888">Battery</span><b>${p.sensor.battery}%</b></div>
          <div style="display:flex;justify-content:space-between;font-size:12px"><span style="color:#888">RSSI</span><b>${p.sensor.rssi} dBm</b></div>
        </div>`,
        { className: "agb-popup" }
      );
      m.addTo(markerLayerRef.current);
    });
  }, [ready, points, showMarkers, metric]);

  // Field boundaries (GeoJSON) drawn over everything
  lmUseEffect(() => {
    if (!ready || !mapRef.current) return;
    const L = window.L;
    if (fieldLayerRef.current) { mapRef.current.removeLayer(fieldLayerRef.current); fieldLayerRef.current = null; }
    if (!showFields) return;
    const m = FIELD_METRICS.ndvi;
    const layer = L.geoJSON(fieldGeo, {
      style: (feat) => {
        if (feat.properties.boundary) {
          return { color: "#ffffff", weight: 2.5, opacity: 0.9, fill: false, dashArray: "6 4" };
        }
        const t = (feat.properties.ndvi - m.min) / (m.max - m.min);
        const col = rgbCss(rampColor(m.ramp, t));
        return { color: col, weight: 1.5, opacity: 0.9, fillColor: col, fillOpacity: 0.18 };
      },
      onEachFeature: (feat, lyr) => {
        const p = feat.properties;
        if (p.boundary) {
          lyr.bindTooltip(`${p.name} · ${p.area_ha} ha`, { permanent: false, direction: "top", className: "agb-tip" });
          return;
        }
        lyr.bindPopup(
          `<div style="font-family:ui-sans-serif;min-width:150px">
            <div style="font-weight:600;font-size:13px">${p.name}</div>
            <div style="color:#888;font-size:11px;margin:2px 0 6px">${p.crop} · ${p.area_ha} ha</div>
            <div style="display:flex;justify-content:space-between;font-size:12px"><span style="color:#888">NDVI</span><b>${p.ndvi}</b></div>
            <div style="display:flex;justify-content:space-between;font-size:12px"><span style="color:#888">Status</span><b>${p.health}</b></div>
          </div>`, { className: "agb-popup" });
        lyr.on("mouseover", () => lyr.setStyle({ weight: 2.5, fillOpacity: 0.34 }));
        lyr.on("mouseout", () => layer.resetStyle(lyr));
      },
    });
    layer.addTo(mapRef.current);
    fieldLayerRef.current = layer;
  }, [ready, fieldGeo, showFields]);

  // Satellite overlay: NASA GIBS tiles OR CDSE backend imagery
  lmUseEffect(() => {
    if (!ready || !mapRef.current) return;
    const L = window.L;
    const map = mapRef.current;
    if (gibsLayerRef.current) { map.removeLayer(gibsLayerRef.current); gibsLayerRef.current = null; }
    if (cdseOverlayRef.current) { map.removeLayer(cdseOverlayRef.current); cdseOverlayRef.current = null; }
    setCdseStatus(null);

    if (gibs === "none") return;

    if (gibs.startsWith("cdse")) {
      const kind = gibs === "cdse_sm" ? "soil-moisture" : "ndvi";
      const url = `${LIVE_CONFIG.cdse_backend}/api/${kind}/tile?farm=${farm.id}`;
      setCdseStatus("loading");
      const ov = L.imageOverlay(url, [[bounds.minLat, bounds.minLng], [bounds.maxLat, bounds.maxLng]], { opacity: 0.82, interactive: false });
      ov.on("load", () => setCdseStatus("live"));
      ov.on("error", () => setCdseStatus("offline"));
      ov.addTo(map);
      cdseOverlayRef.current = ov;
      return;
    }

    if (GIBS_LAYERS[gibs]) {
      const cfg = GIBS_LAYERS[gibs];
      const layer = L.tileLayer(cfg.template.replace("{time}", cfg.time()), {
        maxNativeZoom: cfg.maxNativeZoom, maxZoom: 19, opacity: 0.7, attribution: cfg.attribution,
      });
      layer.addTo(map);
      gibsLayerRef.current = layer;
    }
  }, [ready, gibs]);

  const m = FIELD_METRICS[metric];

  return (
    <div className="card" style={{ padding: 0, overflow: "hidden" }}>
      {/* Toolbar */}
      <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderBottom: "1px solid var(--border)", flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <Icon name="map" size={15} color="var(--primary)" />
          <span style={{ fontSize: 13, fontWeight: 500 }}>{farm.name} — live field</span>
        </div>
        <div style={{ width: 1, height: 20, background: "var(--border)" }} />
        {/* Metric selector */}
        <div style={{ display: "inline-flex", padding: 3, background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 8, gap: 2 }}>
          {Object.keys(FIELD_METRICS).map((k) => (
            <button key={k} onClick={() => setMetric(k)}
              style={{ border: 0, font: "inherit", fontSize: 11, fontWeight: 500, padding: "5px 10px", borderRadius: 6, cursor: "pointer", whiteSpace: "nowrap",
                background: metric === k ? "var(--bg)" : "transparent", color: metric === k ? "var(--text)" : "var(--text-dim)" }}>
              {FIELD_METRICS[k].short}
            </button>
          ))}
        </div>
        <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
          {/* Satellite layer: NASA GIBS + CDSE backend */}
          <label style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11 }} className="dim">
            <Icon name="layers" size={13} /> Satellite
            <select className="input" value={gibs} onChange={(e) => setGibs(e.target.value)} style={{ width: "auto", padding: "4px 26px 4px 8px", fontSize: 11 }}>
              <option value="none">None</option>
              <optgroup label="NASA GIBS (live, free)">
                {Object.keys(GIBS_LAYERS).map((k) => <option key={k} value={k}>{GIBS_LAYERS[k].label}</option>)}
              </optgroup>
              <optgroup label="CDSE / Sentinel (backend)">
                <option value="cdse_ndvi">Sentinel-2 NDVI</option>
                <option value="cdse_sm">Sentinel-1 soil moisture</option>
              </optgroup>
            </select>
          </label>
          {cdseStatus && (
            <span className={"tag " + (cdseStatus === "live" ? "ok" : cdseStatus === "offline" ? "bad" : "warn")} style={{ fontSize: 10 }} title={cdseStatus === "offline" ? "Start the Flask backend in /backend (python app.py)" : ""}>
              {cdseStatus === "live" ? "CDSE live" : cdseStatus === "offline" ? "backend offline" : "loading…"}
            </span>
          )}
          <Toggle label="Fields" on={showFields} onClick={() => setShowFields((v) => !v)} />
          <Toggle label="Heatmap" on={showHeat} onClick={() => setShowHeat((v) => !v)} />
          <Toggle label="Sensors" on={showMarkers} onClick={() => setShowMarkers((v) => !v)} />
          <label style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11 }} className="dim">
            Opacity
            <input type="range" min={0.2} max={1} step={0.02} value={opacity} onChange={(e) => setOpacity(+e.target.value)} style={{ width: 70 }} />
          </label>
        </div>
      </div>

      {/* Map */}
      <div style={{ position: "relative" }}>
        <div ref={mapEl} style={{ height, width: "100%", background: "var(--bg)" }} />
        {/* Legend */}
        <div style={{ position: "absolute", left: 12, bottom: 24, zIndex: 500, background: "color-mix(in oklch, var(--bg-elev) 92%, transparent)", border: "1px solid var(--border-strong)", borderRadius: 10, padding: "10px 12px", backdropFilter: "blur(8px)", pointerEvents: "none", minWidth: 180 }}>
          <div style={{ fontSize: 11, fontWeight: 600, marginBottom: 2 }}>{m.label}</div>
          <div className="dim" style={{ fontSize: 10, marginBottom: 8, maxWidth: 200 }}>{m.desc}</div>
          <div style={{ height: 8, borderRadius: 4, background: `linear-gradient(to right, ${m.ramp.map((c) => rgbCss(c)).join(",")})` }} />
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 4 }}>
            <span className="mono faint" style={{ fontSize: 10 }}>{m.min}{m.unit}</span>
            <span className="mono faint" style={{ fontSize: 10 }}>{m.max}{m.unit}</span>
          </div>
        </div>
        {/* Sensor count badge */}
        <div style={{ position: "absolute", right: 12, top: 12, zIndex: 500, background: "color-mix(in oklch, var(--bg-elev) 92%, transparent)", border: "1px solid var(--border-strong)", borderRadius: 999, padding: "5px 12px", backdropFilter: "blur(8px)", fontSize: 11, display: "flex", alignItems: "center", gap: 8 }}>
          <span className="pulse-dot" style={{ width: 6, height: 6 }} />
          <span className="mono">{sensors.length}</span> <span className="dim">hyperlocal nodes</span>
        </div>
      </div>

      {/* Footnote */}
      <div style={{ padding: "10px 14px", borderTop: "1px solid var(--border)", display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 8 }}>
        <span className="faint" style={{ fontSize: 10 }}>Basemap: Esri · Satellite: NASA GIBS + CDSE Sentinel-2/1 · Fields: GeoJSON · Heatmap: IDW over sensor nodes</span>
        <span className="faint mono" style={{ fontSize: 10 }}>{farm.lat.toFixed(4)}, {farm.lng.toFixed(4)}</span>
      </div>
    </div>
  );
}

function Toggle({ label, on, onClick }) {
  return (
    <button onClick={onClick} style={{ display: "flex", alignItems: "center", gap: 6, border: 0, background: "transparent", cursor: "pointer", font: "inherit", fontSize: 11, color: on ? "var(--text)" : "var(--text-dim)" }}>
      <span style={{ width: 28, height: 16, borderRadius: 999, background: on ? "var(--primary)" : "var(--surface-3)", position: "relative", transition: "background .15s" }}>
        <span style={{ position: "absolute", top: 2, left: on ? 14 : 2, width: 12, height: 12, borderRadius: 999, background: "var(--bg)", transition: "left .15s" }} />
      </span>
      {label}
    </button>
  );
}

// Resolve a CSS var color to a concrete value for Leaflet (which needs real colors)
function colorVar(v) {
  if (!v || !v.startsWith("var(")) return v;
  const name = v.slice(4, -1).trim();
  const val = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
  return val || "#22c55e";
}

// ============ Fleet-wide satellite page ============
function LiveSatellite({ navigate }) {
  const { FARMS, SENSORS } = window.AGB_DATA;
  const [farmId, setFarmId] = lmUseState(FARMS[0].id);
  const farm = FARMS.find((f) => f.id === farmId);
  const sensors = SENSORS.filter((s) => s.farm_id === farmId);

  return (
    <div>
      <PageHeader
        eyebrow="IoT · Satellite & soil"
        title="Live field intelligence"
        sub="Real satellite imagery (Esri + NASA GIBS) fused with hyperlocal Agrobotic sensor readings and live weather, soil, and air data."
        actions={
          <select className="input" value={farmId} onChange={(e) => setFarmId(e.target.value)} style={{ width: "auto" }}>
            {FARMS.map((f) => <option key={f.id} value={f.id}>{f.name} ({f.region})</option>)}
          </select>
        }
      />
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) 360px", gap: 12, padding: "0 var(--space-6) var(--space-6)", alignItems: "start" }}>
        <LiveFieldMap key={farmId} farm={farm} sensors={sensors} height={620} />
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          <LiveEnvPanel key={farmId + "-env"} lat={farm.lat} lng={farm.lng} seed={farm.id.charCodeAt(2)} />
          <CSAPanel />
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { LiveFieldMap, LiveEnvPanel, LiveSatellite, CSAPanel });
