/* ============================================================
   City Analysis mode — split layout matching Homeowner.
   Reuses the global polygon-draw flow (pendingPolygon / setPolygon /
   PolygonToggle) so the action of drawing a polygon is identical
   to homeowner mode.
   ============================================================ */
/* global React, CityMapView, Icon, PolygonToggle, AddrBar */
const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React;

const POLL_INTERVAL_MS = 1500;

function fmtNum(n, digits = 1) {
  if (n == null || !Number.isFinite(n)) return "—";
  if (Math.abs(n) >= 100) return Math.round(n).toLocaleString("en-IN");
  return n.toFixed(digits);
}

/* ---------- Side-panel sections (sp-section blocks) ---------- */

function RegionBlock({ polygon, estimate }) {
  const hasPoly = polygon && polygon.length >= 3;
  return (
    <div className="sp-section">
      <div className="sp-section-head">
        <div className="t-label">Region of interest</div>
        {hasPoly && <div className="t-tag">{polygon.length} pts</div>}
      </div>
      {!hasPoly ? (
        <div className="t-small" style={{ color: "var(--ink-3)" }}>
          Click <b>Draw polygon</b> (bottom-left of the map), then click on the map to add
          vertices. Click the first vertex again to close.
        </div>
      ) : (
        <div className="sp-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
          <div className="sp-cell">
            <div className="k">Bbox area</div>
            <div className="v">{fmtNum(estimate?.bboxKm2, 2)}<span className="u">km²</span></div>
            <div className="delta">bounding box of polygon</div>
          </div>
          <div className="sp-cell">
            <div className="k">Solar API tiles</div>
            <div className="v">{estimate?.tileCount ?? "—"}<span className="u">{estimate?.tileCount === 1 ? "tile" : "tiles"}</span></div>
            <div className="delta">1 km radius · 1 m / pixel</div>
          </div>
        </div>
      )}
    </div>
  );
}

// Side-panel status block. Renders ONLY during 'running' and 'done' — the
// pre-run "Run analysis" action lives in the floating PolygonInfoCard on the
// map (single CTA, mirroring how Homeowner uses LocationPanel for the action
// and the side panel for displayed state).
function StatusBlock({ running, done, onClear, job }) {
  if (!running && !done) return null;
  const progressPct = job ? Math.round((job.progress.done / Math.max(1, job.progress.total)) * 100) : 0;
  return (
    <div className="sp-section">
      <div className="sp-section-head">
        <div className="t-label">{running ? "Running" : "Result"}</div>
        {done && job && (
          <div className="t-tag">{job.tileCount} {job.tileCount === 1 ? "tile" : "tiles"}</div>
        )}
      </div>

      {running && (
        <>
          <div className="row-flex" style={{ justifyContent: "space-between", marginBottom: 8 }}>
            <span className="t-mono" style={{ color: "var(--ink-2)" }}>
              {job.progress.done} / {job.progress.total} tiles
            </span>
            <span className="t-mono" style={{ color: "var(--ink-3)" }}>{progressPct}%</span>
          </div>
          <div style={{
            height: 5, background: "var(--bg-sunken)", borderRadius: 3, overflow: "hidden",
          }}>
            <div style={{
              width: `${progressPct}%`, height: "100%",
              background: "var(--accent-strong)", transition: "width 0.4s",
            }}/>
          </div>
          <div className="t-tiny" style={{ marginTop: 6, color: "var(--ink-3)" }}>
            Fetching annual-flux GeoTIFFs · cached on disk for re-runs
          </div>
        </>
      )}

      {done && (
        <>
          <div className="row-flex" style={{ gap: 8, marginBottom: 10 }}>
            <span className="tag pos">Done</span>
            <span className="t-mono" style={{ color: "var(--ink-3)" }}>BASE quality</span>
          </div>
          <button className="btn" onClick={onClear} style={{ width: "100%", justifyContent: "center" }}>
            <Icon name="x" size={11} color="currentColor"/>
            Clear polygon & start over
          </button>
        </>
      )}
    </div>
  );
}

function ResultsBlock({ kpis, status }) {
  const ready = status === "done" && kpis;
  return (
    <div className="sp-section">
      <div className="sp-section-head">
        <div className="t-label">Headline KPIs</div>
        <div className="t-tag">municipal planner</div>
      </div>

      <div className="sp-grid">
        <div className="sp-cell">
          <div className="k">Polygon area</div>
          <div className="v">{ready ? fmtNum(kpis.totalAreaKm2, 2) : "—"}<span className="u">km²</span></div>
          <div className="delta">analysed surface (clipped)</div>
        </div>
        <div className="sp-cell">
          <div className="k">Suitable area</div>
          <div className="v">{ready ? fmtNum(kpis.suitableAreaKm2, 2) : "—"}<span className="u">km²</span></div>
          <div className="delta">
            {ready ? `${Math.round((kpis.suitableFraction || 0) * 100)}% of polygon · flux ≥ 1400` : "kWh/kW/yr threshold"}
          </div>
        </div>
        <div className="sp-cell">
          <div className="k">Mean flux</div>
          <div className="v">{ready ? fmtNum(kpis.meanFluxKwhPerKwYr, 0) : "—"}<span className="u">kWh/kW/yr</span></div>
          <div className="delta">{ready ? `P90 ${fmtNum(kpis.p90FluxKwhPerKwYr, 0)}` : "annual irradiance"}</div>
        </div>
        <div className="sp-cell">
          <div className="k">Potential capacity</div>
          <div className="v">{ready ? fmtNum((kpis.totalKwp || 0) / 1000, 1) : "—"}<span className="u">MW</span></div>
          <div className="delta">@ 165 W/m², suitable pixels only</div>
        </div>
        <div className="sp-cell">
          <div className="k">Annual generation</div>
          <div className="v">{ready ? fmtNum(kpis.yearlyGwh, 2) : "—"}<span className="u">GWh/yr</span></div>
          <div className="delta">after 80% derate</div>
        </div>
        <div className="sp-cell">
          <div className="k">CO₂ offset</div>
          <div className="v">{ready ? fmtNum((kpis.co2OffsetTonnesPerYear || 0) / 1000, 1) : "—"}<span className="u">kt/yr</span></div>
          <div className="delta">India grid · 0.82 kg/kWh</div>
        </div>
      </div>
    </div>
  );
}

function SourcesBlock({ done }) {
  return (
    <div className="sp-section">
      <div className="sp-section-head">
        <div className="t-label">Method</div>
      </div>
      <div className="t-small" style={{ color: "var(--ink-3)", lineHeight: 1.55 }}>
        Polygon's bbox is covered by <b>1 km-radius disks</b>. For each disk we call Solar API
        <code style={{ fontFamily: "var(--font-mono)", fontSize: 11, padding: "1px 4px", background: "var(--bg-sunken)", borderRadius: 3, margin: "0 3px" }}>dataLayers:get</code>
        at <b>1 m / pixel</b> for the annual-flux + mask GeoTIFFs. Tiles are mosaiced and clipped
        to your polygon. Annual flux is computed for <i>every</i> location (not just rooftops), so
        the heatmap covers ground too — that's what makes solar-farm screening possible.
      </div>
    </div>
  );
}

/* ---------- Bottom-left card on the map when polygon is set ---------- */
function PolygonInfoCard({ polygon, estimate, pendingRun, running, done, onRun, onClear }) {
  if (running || done) return null;
  if (!polygon || polygon.length < 3) return null;
  const cx = polygon.reduce((a, p) => a + p.lat, 0) / polygon.length;
  const cy = polygon.reduce((a, p) => a + p.lng, 0) / polygon.length;
  const requireConfirm = estimate?.requiresConfirmation;
  return (
    <div style={{
      position: "absolute", left: 268, bottom: 14, zIndex: 1000,
      width: 360,
      background: "var(--bg-elev)", border: "1px solid var(--line-strong)",
      borderRadius: 8, boxShadow: "0 8px 24px rgba(0,0,0,0.10)",
      padding: 12,
    }}>
      <div className="t-label" style={{ marginBottom: 8, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <span>Drawn polygon</span>
        <span className="t-tag" style={{ background: "var(--bg-sunken)" }}>{polygon.length} pts</span>
      </div>
      <div className="t-mono" style={{ color: "var(--ink-3)", marginBottom: 4 }}>
        centroid {cx.toFixed(5)}°N · {cy.toFixed(5)}°E
      </div>
      {estimate && (
        <div className="t-mono" style={{ color: "var(--ink-3)", marginBottom: 10 }}>
          ~{estimate.tileCount} tiles · est. ${fmtNum(estimate.estimatedCostUsd, 2)}
          {requireConfirm && <span style={{ color: "var(--accent-strong)" }}> · confirm to run</span>}
        </div>
      )}
      <div style={{ display: "flex", gap: 6 }}>
        <button
          className="btn primary"
          onClick={onRun}
          disabled={pendingRun}
          style={{ flex: 1, justifyContent: "center", opacity: pendingRun ? 0.7 : 1 }}
        >
          {pendingRun ? (
            <>
              <span style={{
                display: "inline-block", width: 10, height: 10, borderRadius: "50%",
                border: "1.5px solid white", borderTopColor: "transparent",
                animation: "lpspin 0.8s linear infinite",
              }}/>
              Starting…
            </>
          ) : (
            <>
              <Icon name="sun" size={12} color="currentColor"/>
              {requireConfirm ? "Run anyway" : "Run analysis"}
            </>
          )}
        </button>
        <button className="btn" onClick={onClear} disabled={pendingRun}>
          <Icon name="x" size={11} color="currentColor"/>
        </button>
      </div>
    </div>
  );
}

/* ---------- Main ---------- */
function CityMode() {
  const data = window.useLeptonData();
  const pendingPolygon = data.pendingPolygon;
  const selectionMode = data.selectionMode;

  const [job, setJob] = useStateC(null);
  const [estimate, setEstimate] = useStateC(null);
  const [pendingRun, setPendingRun] = useStateC(false);
  const [error, setError] = useStateC(null);
  const pollRef = useRefC(null);
  const autoFitRef = useRefC(true);

  // On mount: enter polygon-draw mode if there's nothing pending — makes the
  // main interaction discoverable. On unmount: clear the polygon from the global
  // store so it doesn't leak to Homeowner (where the same `pendingPolygon` slot
  // means "building outline override", which is a different concept).
  useEffectC(() => {
    if (selectionMode !== "polygon" && !pendingPolygon) {
      window.LEPTON_LOAD.setSelectionMode("polygon");
    }
    return () => {
      if (pollRef.current) clearInterval(pollRef.current);
      window.LEPTON_LOAD.clearPending();
    };
    // eslint-disable-next-line
  }, []);

  // Whenever polygon changes, refresh cost estimate (cheap, server-side computed
  // from bbox math — no Solar API calls).
  useEffectC(() => {
    if (!pendingPolygon || pendingPolygon.length < 3) {
      setEstimate(null);
      setJob(null);
      return;
    }
    let cancelled = false;
    (async () => {
      try {
        const r = await fetch("/api/city-analysis/estimate", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ polygon: pendingPolygon.map(p => [p.lat, p.lng]) }),
        });
        if (cancelled || !r.ok) return;
        setEstimate(await r.json());
      } catch (e) { /* ignore */ }
    })();
    return () => { cancelled = true; };
  }, [pendingPolygon]);

  function startPolling(jobId) {
    if (pollRef.current) clearInterval(pollRef.current);
    pollRef.current = setInterval(async () => {
      try {
        const r = await fetch(`/api/city-analysis/${jobId}`);
        if (!r.ok) throw new Error(`status ${r.status}`);
        const j = await r.json();
        setJob(j);
        if (j.status === "done" || j.status === "error") {
          clearInterval(pollRef.current);
          pollRef.current = null;
          if (j.status === "error") setError(j.error || "analysis failed");
        }
      } catch (e) {
        clearInterval(pollRef.current); pollRef.current = null;
        setError(String(e.message || e));
      }
    }, POLL_INTERVAL_MS);
  }

  async function runAnalysis() {
    if (!pendingPolygon || pendingPolygon.length < 3) return;
    setPendingRun(true);
    setError(null);
    try {
      const r = await fetch("/api/city-analysis", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ polygon: pendingPolygon.map(p => [p.lat, p.lng]) }),
      });
      if (!r.ok) throw new Error(`start failed (${r.status})`);
      const j = await r.json();
      setJob({
        jobId: j.jobId, status: "queued",
        progress: { done: 0, total: j.tileCount },
        tileCount: j.tileCount,
      });
      startPolling(j.jobId);
    } catch (e) {
      setError(String(e.message || e));
    } finally {
      setPendingRun(false);
    }
  }

  function clearAll() {
    if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; }
    setJob(null);
    setEstimate(null);
    setError(null);
    window.LEPTON_LOAD.clearPending();           // clears polygon AND pendingLocation
    window.LEPTON_LOAD.setSelectionMode("polygon"); // stay in draw mode
    autoFitRef.current = true;
  }

  const running = job && (job.status === "running" || job.status === "queued");
  const done = job && job.status === "done";

  // Auto-fit camera to polygon only on initial polygon creation, not on every
  // re-render — otherwise the camera fights the user's zoom while running.
  const autoFit = autoFitRef.current && !running && !done;
  useEffectC(() => {
    if (pendingPolygon) autoFitRef.current = false;
  }, [pendingPolygon]);

  return (
    <div className="split">
      {/* MAP */}
      <div className="split-map">
        <CityMapView
          pendingPolygon={pendingPolygon}
          selectionMode={selectionMode}
          heatmapUrl={done ? job.heatmapUrl : null}
          heatmapBounds={done ? job.heatmapBounds : null}
          autoFitOnPolygon={autoFit}
        />
        {/* Same place / lat-lng search as homeowner. skipSetPending so a search
            doesn't create a stray pin (CityMode only needs the map to pan). */}
        <AddrBar
          building={null}
          placeholder="Search city, area or lat, lng (e.g. 28.49, 77.09)"
          skipSetPending={true}
          defaultZoom={15}
        />
        {/* Same draw-polygon pill as homeowner mode. */}
        <PolygonToggle selectionMode={selectionMode} />

        {/* Bottom-left card with polygon info + run button (mirrors LocationPanel UX). */}
        <PolygonInfoCard
          polygon={pendingPolygon}
          estimate={estimate}
          pendingRun={pendingRun}
          running={running}
          done={done}
          onRun={runAnalysis}
          onClear={clearAll}
        />

        {/* Flux legend (bottom-right) once heatmap is up. */}
        {done && (
          <div className="maplegend" style={{ bottom: 14, right: 12 }}>
            <div className="head">Annual flux (kWh/kW/yr)</div>
            <div className="ramp"></div>
            <div className="axis"><span>low</span><span>high</span></div>
          </div>
        )}
      </div>

      {/* SIDE PANEL — display only; the Run action lives in the floating card. */}
      <div className="split-panel">
        <RegionBlock polygon={pendingPolygon} estimate={estimate} />
        <StatusBlock running={running} done={done} onClear={clearAll} job={job} />
        <ResultsBlock kpis={job?.kpis} status={job?.status} />
        {error && (
          <div className="sp-section">
            <div className="t-tiny" style={{
              padding: "8px 10px", borderRadius: 6,
              background: "var(--neg-soft)", color: "var(--neg)",
            }}>
              {error}
            </div>
          </div>
        )}
        <SourcesBlock done={done}/>
      </div>
    </div>
  );
}

window.CityMode = CityMode;
