/* global React */
/* =====================================================================
   Shared editorial primitives + local capture store
   Editorial Signal — sharp edges, hairlines, mono coordinates.
   ===================================================================== */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- Capture store (localStorage) --------------------------------- */
const STORE_KEY = "sounding-line.capture.v1";
function readStore() {
  try { return JSON.parse(localStorage.getItem(STORE_KEY) || "{}"); }
  catch (e) { return {}; }
}
function writeStore(obj) {
  try { localStorage.setItem(STORE_KEY, JSON.stringify(obj)); } catch (e) {}
  window.dispatchEvent(new CustomEvent("capture-change"));
}
function useCapture(id, fallback) {
  const [val, setVal] = useState(() => {
    const s = readStore();
    return id in s ? s[id] : fallback;
  });
  const set = useCallback((v) => {
    setVal(v);
    const s = readStore();
    s[id] = v;
    writeStore(s);
  }, [id]);
  useEffect(() => {
    const sync = () => {
      const s = readStore();
      setVal((cur) => (id in s ? s[id] : cur));
    };
    window.addEventListener("capture-change", sync);
    return () => window.removeEventListener("capture-change", sync);
  }, [id]);
  return [val, set];
}

/* ---- Eyebrow / mono kicker ---------------------------------------- */
function Eyebrow({ children, style, signal }) {
  return (
    <div style={{
      fontFamily: "var(--font-mono)", fontSize: 12, textTransform: "uppercase",
      letterSpacing: "0.14em", color: signal ? "var(--signal)" : "var(--fg2)",
      lineHeight: 1, ...style,
    }}>{children}</div>
  );
}

/* ---- Functional icons (1.5px stroke) ------------------------------ */
function Icon({ name, size = 18, style }) {
  const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round",
    strokeLinejoin: "round", style, "aria-hidden": true };
  const paths = {
    arrowDown: <><line x1="12" y1="4" x2="12" y2="20" /><polyline points="6 14 12 20 18 14" /></>,
    arrowUp: <><line x1="12" y1="20" x2="12" y2="4" /><polyline points="6 10 12 4 18 10" /></>,
    arrowRight: <><line x1="4" y1="12" x2="20" y2="12" /><polyline points="14 6 20 12 14 18" /></>,
    arrowLeft: <><line x1="20" y1="12" x2="4" y2="12" /><polyline points="10 6 4 12 10 18" /></>,
    plus: <><line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /></>,
    minus: <line x1="5" y1="12" x2="19" y2="12" />,
    grid: <><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /><rect x="14" y="14" width="7" height="7" /></>,
    layers: <><polygon points="12 2 22 8.5 12 15 2 8.5 12 2" /><polyline points="2 15.5 12 22 22 15.5" /></>,
    check: <polyline points="20 6 9 17 4 12" />,
    x: <><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></>,
    chevR: <polyline points="9 6 15 12 9 18" />,
  };
  return <svg {...common}>{paths[name]}</svg>;
}

/* ---- Hairline rule ------------------------------------------------- */
function Rule({ soft, thick, style }) {
  return <div style={{
    height: 0, borderTop: `${thick ? 3 : 1}px solid ${soft ? "var(--fog)" : "var(--ink)"}`,
    width: "100%", ...style,
  }} />;
}

/* ---- Serif editorial fragment ------------------------------------- */
function Serif({ children, style }) {
  return <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic",
    letterSpacing: 0, ...style }}>{children}</span>;
}

/* ---- Reveal panel: hidden analysis, shown on demand --------------- */
function Reveal({ label = "Reveal the deeper analysis", children, inverse }) {
  const [open, setOpen] = useState(false);
  const line = inverse ? "var(--paper)" : "var(--ink)";
  return (
    <div style={{ borderTop: `1px solid ${inverse ? "rgba(242,240,235,0.25)" : "var(--fog)"}`, marginTop: 4 }}>
      <button
        onClick={() => setOpen(!open)}
        className="focus-ring"
        style={{
          all: "unset", cursor: "pointer", display: "flex", alignItems: "center", gap: 12,
          padding: "16px 0", color: line, width: "100%",
          fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.12em",
          textTransform: "uppercase",
        }}>
        <span style={{
          width: 20, height: 20, border: `1px solid ${line}`, display: "inline-flex",
          alignItems: "center", justifyContent: "center", flex: "0 0 auto",
          transition: "background var(--dur-fast) var(--ease)",
        }}>
          <Icon name={open ? "minus" : "plus"} size={12} />
        </span>
        <span style={{ opacity: 0.85 }}>{open ? "Hide analysis" : label}</span>
      </button>
      <div style={{
        display: "grid",
        gridTemplateRows: open ? "1fr" : "0fr",
        transition: "grid-template-rows var(--dur) var(--ease)",
      }}>
        <div style={{ overflow: "hidden", minHeight: 0 }}>
          <div style={{ paddingBottom: 28, opacity: open ? 1 : 0, transition: "opacity var(--dur) var(--ease)" }}>
            {children}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ---- Analysis blocks (from data.analysis) ------------------------- */
function AnalysisBody({ analysis, inverse }) {
  const soft = inverse ? "rgba(242,240,235,0.6)" : "var(--fg2)";
  const strong = inverse ? "var(--paper)" : "var(--ink)";
  return (
    <div style={{ maxWidth: "64ch" }}>
      <Eyebrow style={{ color: "var(--signal)", marginBottom: 18 }}>{analysis.title}</Eyebrow>
      <div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
        {analysis.blocks.map((b, i) => (
          <div key={i}>
            {b.rule && (
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.12em",
                textTransform: "uppercase", color: soft, marginBottom: 10 }}>{b.rule}</div>
            )}
            {b.lines && (
              <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex",
                flexDirection: "column", gap: 9 }}>
                {b.lines.map((l, j) => (
                  <li key={j} style={{ display: "flex", gap: 12, color: strong,
                    fontSize: 16, lineHeight: 1.5 }}>
                    <span style={{ color: "var(--signal)", flex: "0 0 auto",
                      fontFamily: "var(--font-mono)", fontSize: 12, paddingTop: 3 }}>—</span>
                    <span>{l}</span>
                  </li>
                ))}
              </ul>
            )}
            {b.quote && (
              <div style={{ borderLeft: "3px solid var(--signal)", padding: "2px 0 2px 22px",
                fontFamily: "var(--font-serif)", fontStyle: "italic", fontSize: 21,
                lineHeight: 1.4, color: strong, maxWidth: "54ch" }}>{b.quote}</div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---- Capture: short text input ------------------------------------ */
function CaptureText({ id, prompt, placeholder, inverse }) {
  const [val, setVal] = useCapture("text:" + id, "");
  const line = inverse ? "rgba(242,240,235,0.4)" : "var(--ink)";
  const lab = inverse ? "rgba(242,240,235,0.6)" : "var(--fg2)";
  return (
    <div style={{ maxWidth: 620 }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.12em",
        textTransform: "uppercase", color: "var(--signal)", marginBottom: 14,
        display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ width: 18, height: 18, border: "1px solid var(--signal)",
          display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
          <Icon name="arrowRight" size={11} />
        </span>
        Capture · saved on this device
      </div>
      <label style={{ display: "block", color: inverse ? "var(--paper)" : "var(--ink)",
        fontSize: 18, marginBottom: 12, fontWeight: 500 }}>{prompt}</label>
      <textarea
        value={val} onChange={(e) => setVal(e.target.value)} rows={2}
        placeholder={placeholder}
        className="focus-ring"
        style={{
          width: "100%", background: "transparent", border: 0, borderBottom: `1px solid ${line}`,
          borderRadius: 0, color: inverse ? "var(--paper)" : "var(--ink)", padding: "10px 2px",
          fontFamily: "var(--font-sans)", fontSize: 18, lineHeight: 1.5, resize: "none",
          outline: "none",
        }} />
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.1em",
        color: lab, marginTop: 8, textTransform: "uppercase",
        opacity: val ? 1 : 0, transition: "opacity var(--dur)" }}>Recorded</div>
    </div>
  );
}

/* ---- Stop wrapper (entrance handled in CSS, never gates visibility) */
function Rise({ children, k }) {
  return <div className="sl-stop">{children}</div>;
}

Object.assign(window, {
  useCapture, readStore, writeStore,
  Eyebrow, Icon, Rule, Serif, Reveal, AnalysisBody, CaptureText, Rise,
});
