/* ============================================================
   FOODMAP — bespoke charts (no chart library)
   ============================================================ */
const { useState, useEffect, useRef, useMemo } = React;
const F = window.FOOD;

/* ---------- hooks ---------- */
function useInView(opts) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reveal = () => { if (!done) { done = true; setSeen(true); } };
    const check = () => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight * 0.9 && r.bottom > 0) reveal();
    };
    const obs = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { reveal(); obs.disconnect(); } },
      { rootMargin: "0px 0px -10% 0px", threshold: 0.12, ...(opts || {}) }
    );
    obs.observe(el);
    check(); // catch already-in-view + programmatic jumps
    window.addEventListener("scroll", check, { passive: true });
    return () => { obs.disconnect(); window.removeEventListener("scroll", check); };
  }, []);
  return [ref, seen];
}

/* ---------- geo helpers ---------- */
const MAPW = 600, MAPH = 320;
function project(lat, lng) {
  // equirectangular, slightly cropped to land band
  const x = ((lng + 180) / 360) * MAPW;
  const y = ((90 - lat) / 180) * MAPH;
  return [x, y];
}
function arcPath(a, b, curve = 0.28) {
  const [x1, y1] = a, [x2, y2] = b;
  const mx = (x1 + x2) / 2, my = (y1 + y2) / 2;
  const dx = x2 - x1, dy = y2 - y1;
  const len = Math.hypot(dx, dy) || 1;
  const nx = -dy / len, ny = dx / len;
  const lift = len * curve;
  // always bow upward-ish for a consistent flight feel
  const sign = y1 + y2 > MAPH ? -1 : -1;
  const cx = mx + nx * lift * sign;
  const cy = my + ny * lift * sign;
  return `M${x1.toFixed(1)},${y1.toFixed(1)} Q${cx.toFixed(1)},${cy.toFixed(1)} ${x2.toFixed(1)},${y2.toFixed(1)}`;
}

/* faint equirectangular graticule = "map without coastlines" */
function Graticule() {
  const lines = [];
  for (let lng = -150; lng <= 150; lng += 30) {
    const [x] = project(0, lng);
    lines.push(<line key={"v" + lng} x1={x} y1={0} x2={x} y2={MAPH} stroke="var(--line)" strokeWidth="1" />);
  }
  for (let lat = -60; lat <= 80; lat += 30) {
    const [, y] = project(lat, 0);
    lines.push(<line key={"h" + lat} x1={0} y1={y} x2={MAPW} y2={y} stroke="var(--line)" strokeWidth="1" />);
  }
  // tropics band (where most of the export crops grow)
  const [, yN] = project(23.5, 0);
  const [, yS] = project(-23.5, 0);
  return (
    <g>
      {/* faint landmasses behind the grid — Natural Earth 110m, same equirectangular projection */}
      {window.WORLD_LAND && (
        <path d={window.WORLD_LAND} fillRule="evenodd" fill="var(--line)"
          stroke="var(--line-strong)" strokeWidth="0.4" strokeOpacity="0.55" />
      )}
      <rect x={0} y={yN} width={MAPW} height={yS - yN} fill="var(--c-yellow)" opacity="0.07" />
      {lines}
      <line x1={0} y1={(yN + yS) / 2} x2={MAPW} y2={(yN + yS) / 2} stroke="var(--line-strong)" strokeWidth="1" strokeDasharray="3 4" />
    </g>
  );
}

/* ============================================================
   FLOW MAP  (section 5 — overlay scrolly, switches commodity)
   ============================================================ */
function FlowMap({ commodity }) {
  const set = F.FLOWS[commodity] || F.FLOWS.coffee;
  // collect nodes used by this commodity
  const exporters = new Set(set.flows.map((f) => f.from));
  const importers = new Set(set.flows.map((f) => f.to));
  const allKeys = new Set([...exporters, ...importers]);

  return (
    <div style={{ width: "100%", maxWidth: 1000, margin: "0 auto" }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 14, justifyContent: "center", marginBottom: 6, flexWrap: "wrap" }}>
        <span className="label" style={{ color: "#9a9486" }}>Global trade flows ·</span>
        <span style={{ fontFamily: "var(--display)", fontWeight: 900, fontSize: "2rem", color: set.color, letterSpacing: "-0.02em" }}>
          {set.label}
        </span>
      </div>
      <svg viewBox={`0 0 ${MAPW} ${MAPH}`} style={{ width: "100%", height: "auto", overflow: "visible" }} role="img" aria-label={`Trade flow map for ${set.label}`}>
        <defs>
          <marker id="ah" markerWidth="7" markerHeight="7" refX="5.5" refY="3" orient="auto">
            <path d="M0,0 L6,3 L0,6 Z" fill={set.color} />
          </marker>
        </defs>
        <Graticule />

        {/* all dormant nodes faint */}
        {Object.keys(F.PLACES).map((k) => {
          const p = F.PLACES[k];
          const [x, y] = project(p.lat, p.lng);
          const active = allKeys.has(k);
          if (active) return null;
          return <circle key={k} cx={x} cy={y} r={2} fill="var(--line-strong)" />;
        })}

        {/* flows */}
        {set.flows.map((f, i) => {
          const a = project(F.PLACES[f.from].lat, F.PLACES[f.from].lng);
          const b = project(F.PLACES[f.to].lat, F.PLACES[f.to].lng);
          const d = arcPath(a, b, 0.26);
          return (
            <g key={commodity + i}>
              <path d={d} fill="none" stroke={set.color} strokeOpacity="0.22" strokeWidth={f.v * 0.9 + 1.5} strokeLinecap="round" />
              <path className="flow-dash" d={d} fill="none" stroke={set.color} strokeWidth={f.v * 0.55 + 1} strokeLinecap="round"
                markerEnd="url(#ah)"
                style={{ strokeDasharray: "5 9", animation: `flow ${2.4 - f.v * 0.08}s linear infinite`, animationDelay: `${i * 0.18}s` }} />
            </g>
          );
        })}

        {/* exporter nodes */}
        {[...exporters].map((k) => {
          const p = F.PLACES[k];
          const [x, y] = project(p.lat, p.lng);
          return (
            <g key={"ex" + k}>
              <circle cx={x} cy={y} r={5} fill={set.color} stroke="#0f0e0b" strokeWidth="1.5" />
              <text x={x} y={y - 9} textAnchor="middle" style={{ fontFamily: "var(--mono)", fontSize: 9, fontWeight: 700, fill: "#f3eee2" }}>{p.name}</text>
            </g>
          );
        })}
        {/* importer nodes */}
        {[...importers].map((k) => {
          if (exporters.has(k)) return null;
          const p = F.PLACES[k];
          const [x, y] = project(p.lat, p.lng);
          return (
            <g key={"im" + k}>
              <circle cx={x} cy={y} r={3.2} fill="#1c1a15" stroke="#b8b2a4" strokeWidth="1.5" />
              <text x={x} y={y + 13} textAnchor="middle" style={{ fontFamily: "var(--mono)", fontSize: 8.5, fill: "#b0a995" }}>{p.name}</text>
            </g>
          );
        })}
      </svg>
      <div style={{ display: "flex", gap: 20, justifyContent: "center", marginTop: 4, flexWrap: "wrap" }}>
        <span className="label" style={{ color: "#cfc8b8", display: "inline-flex", alignItems: "center", gap: 7 }}>
          <span style={{ width: 11, height: 11, borderRadius: "50%", background: set.color, border: "1.5px solid #0f0e0b" }}></span> exporter
        </span>
        <span className="label" style={{ color: "#cfc8b8", display: "inline-flex", alignItems: "center", gap: 7 }}>
          <span style={{ width: 9, height: 9, borderRadius: "50%", background: "#1c1a15", border: "1.5px solid #b8b2a4" }}></span> importer
        </span>
        <span className="label" style={{ color: "#9a9486" }}>arrow width ≈ volume</span>
      </div>
    </div>
  );
}

/* ============================================================
   COFFEE JOURNEY (section 2 — split scrolly, evolves by step)
   step 0: bean belt   1: producers   2: exports   3: mismatch
   ============================================================ */
const COFFEE_NODES = ["brazil", "vietnam", "colombia", "indonesia", "ethiopia"];
const COFFEE_DEST = ["usa", "eu", "japan", "finland"];
function CoffeeJourney({ step }) {
  const C = F.COFFEE;
  const showBelt = step >= 0;
  const showProducers = step >= 1;
  const showArcs = step >= 2;
  const showDest = step >= 3;
  const prodMax = Math.max(...C.producers.filter((p) => p.key !== "others").map((p) => p.value));

  return (
    <div className="chart-frame" style={{ padding: "18px 18px 16px" }}>
      <div className="chart-title">The bean's commute</div>
      <div className="chart-sub">green coffee · exports → cup</div>
      <svg viewBox={`0 0 ${MAPW} ${MAPH}`} style={{ width: "100%", height: "auto", marginTop: 8, overflow: "visible" }}>
        <Graticule />
        {/* bean belt callout */}
        {showBelt && (
          <text x={6} y={project(23.5, 0)[1] - 5} className="annot" style={{ fontSize: 8.5, fontWeight: 700, fill: "var(--c-coffee)" }}>
            ↕ the "bean belt" · ±23.5°
          </text>
        )}

        {/* arcs to destinations */}
        {showArcs && COFFEE_NODES.map((k) =>
          COFFEE_DEST.map((d, j) => {
            // only draw a couple representative arcs
            if (!((k === "brazil") || (k === "vietnam" && d === "eu") || (k === "colombia" && d === "usa") || (k === "ethiopia" && d === "eu"))) return null;
            const a = project(F.PLACES[k].lat, F.PLACES[k].lng);
            const b = project(F.PLACES[d].lat, F.PLACES[d].lng);
            const path = arcPath(a, b, 0.26);
            return (
              <path key={k + d} d={path} fill="none" stroke="var(--c-coffee)" strokeWidth="1.6" strokeLinecap="round"
                style={{ strokeDasharray: "4 7", animation: "flow 2.2s linear infinite", animationDelay: `${j * 0.2}s`, opacity: 0.8 }} />
            );
          })
        )}

        {/* destination nodes */}
        {showDest && COFFEE_DEST.map((d) => {
          const p = F.PLACES[d];
          const [x, y] = project(p.lat, p.lng);
          return (
            <g key={"d" + d}>
              <circle cx={x} cy={y} r={3.2} fill="#fff" stroke="var(--ink)" strokeWidth="1.5" />
              <text x={x} y={y - 7} textAnchor="middle" className="annot-soft" style={{ fontSize: 7.5 }}>{p.name}</text>
            </g>
          );
        })}

        {/* producer nodes sized by output */}
        {showProducers && C.producers.filter((p) => p.key !== "others").map((p) => {
          const pl = F.PLACES[p.key];
          const [x, y] = project(pl.lat, pl.lng);
          const r = 3 + (p.value / prodMax) * 9;
          return (
            <g key={p.key} style={{ transition: "all 0.5s ease" }}>
              <circle cx={x} cy={y} r={r} fill={p.color} stroke="var(--ink)" strokeWidth="1.5" opacity="0.92" />
              <text x={x} y={y + r + 9} textAnchor="middle" className="annot" style={{ fontSize: 8, fontWeight: 700 }}>
                {pl.name} {p.value}%
              </text>
            </g>
          );
        })}
      </svg>

      {/* importer mini-bars appear at last step */}
      {showDest && (() => {
        const impMax = Math.max(...C.importers.map((c) => c.value));
        return (
          <div style={{ marginTop: 10, borderTop: "2px solid var(--line)", paddingTop: 10 }}>
            <div className="label" style={{ marginBottom: 8 }}>coffee imported, 2024 · grows almost ZERO beans</div>
            {C.importers.slice(0, 4).map((c) => (
              <div key={c.label} style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 5 }}>
                <span className="mono" style={{ fontSize: 11, width: 84, textAlign: "right", flexShrink: 0 }}>{c.label}</span>
                <div style={{ flex: 1, background: "var(--bg-warm)", borderRadius: 3, height: 12, overflow: "hidden" }}>
                  <div style={{ width: `${(c.value / impMax) * 100}%`, height: "100%", background: "var(--c-coffee)", transition: "width 0.7s ease" }}></div>
                </div>
                <span className="mono" style={{ fontSize: 11, width: 42 }}>${c.value}B</span>
              </div>
            ))}
          </div>
        );
      })()}
    </div>
  );
}

/* ============================================================
   CONCENTRATION BARS (section 3 — split scrolly, highlight crop)
   ============================================================ */
function ConcentrationBars({ step }) {
  const rows = F.CONCENTRATION;
  return (
    <div className="chart-frame">
      <div className="chart-title">Who controls the harvest</div>
      <div className="chart-sub">share of world exports · top suppliers vs. everyone else</div>
      <div style={{ marginTop: 18 }}>
        {rows.map((r, i) => {
          const active = step === i;
          const top3 = r.top.reduce((s, t) => s + t.v, 0);
          let acc = 0;
          return (
            <div key={r.crop} style={{ marginBottom: 16, opacity: active ? 1 : 0.42, transition: "opacity 0.4s ease" }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 5 }}>
                <span style={{ fontFamily: "var(--display)", fontWeight: 800, fontSize: "1rem" }}>{r.crop}</span>
                <span className="mono" style={{ fontSize: 12, color: r.color, fontWeight: 700 }}>{top3}% from {r.top.length}</span>
              </div>
              <div style={{ display: "flex", height: 26, border: "2px solid var(--ink)", borderRadius: 4, overflow: "hidden", background: "#fff" }}>
                {r.top.map((t, j) => {
                  const seg = (
                    <div key={j} title={`${t.c} ${t.v}%`}
                      style={{ width: `${t.v}%`, background: r.color, opacity: 1 - j * 0.22, borderRight: "1.5px solid var(--ink)",
                        display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", transition: "width 0.6s ease" }}>
                      {t.v >= 14 && <span className="mono" style={{ fontSize: 9.5, color: "#fff", fontWeight: 700, whiteSpace: "nowrap" }}>{t.c}</span>}
                    </div>
                  );
                  acc += t.v;
                  return seg;
                })}
                <div style={{ width: `${r.rest}%`, background: "repeating-linear-gradient(45deg,#efe9da,#efe9da 4px,#e4ddcd 4px,#e4ddcd 8px)",
                  display: "flex", alignItems: "center", justifyContent: "center" }}>
                  {r.rest >= 16 && <span className="mono" style={{ fontSize: 9.5, color: "var(--ink-soft)" }}>rest of world</span>}
                </div>
              </div>
              {active && <div className="mono" style={{ fontSize: 12, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.4 }}>↑ {r.note}</div>}
            </div>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, { useInView, FlowMap, CoffeeJourney, ConcentrationBars, project, arcPath, Graticule, useState, useEffect, useRef, useMemo });
