/* ============================================================
   RESTO SUITE — SHARED CORE
   Schema: ONE plan object in localStorage under "resto.plan.v1"
     plan = { idea, market, location, validation, financials, meta }
   Each module edits ONLY its own namespace; reads others read-only.
   Migrates legacy "resto.v3" (standalone financial tool) → plan.financials.
   ============================================================ */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- format helpers ---------- */
const fmt = (n) => (isFinite(n) ? Math.round(n).toLocaleString("en-US") : "—");
const fmtBaht = (n) => "฿" + fmt(n);
const fmtPct = (n, d = 0) => (isFinite(n) ? (n * 100).toFixed(d) + "%" : "—");
const fmtMonths = (n) => {
  if (!isFinite(n) || n <= 0) return "—";
  if (n < 24) return Math.round(n) + " mo";
  return (n / 12).toFixed(1) + " yr";
};
const parseNum = (s) => {
  const v = parseFloat(String(s).replace(/[^0-9.]/g, ""));
  return isNaN(v) ? 0 : v;
};
const money = (n) => (isFinite(n) && n !== 0 ? fmtBaht(Math.abs(n)) : "—");

/* ---------- tones ---------- */
const toneVar = (t, kind) => {
  const map = {
    green: { fg: "var(--green)", bg: "var(--green-tint)", bd: "rgba(62,142,90,.28)" },
    red: { fg: "var(--red)", bg: "var(--red-tint)", bd: "rgba(194,72,59,.28)" },
    amber: { fg: "var(--amber)", bg: "var(--amber-tint)", bd: "rgba(183,121,31,.28)" },
    muted: { fg: "var(--muted)", bg: "var(--surface-2)", bd: "var(--border)" },
  };
  return (map[t] || map.muted)[kind];
};

/* ---------- hooks ---------- */
function useMedia(q) {
  const [m, setM] = useState(() => (typeof matchMedia !== "undefined" ? matchMedia(q).matches : false));
  useEffect(() => {
    const mm = matchMedia(q); const h = (e) => setM(e.matches);
    mm.addEventListener("change", h); setM(mm.matches);
    return () => mm.removeEventListener("change", h);
  }, [q]);
  return m;
}

/* ============================================================
   PLAN STORE
   ============================================================ */
const PLAN_KEY = "resto.plan.v1";

const FIN_DEFAULTS = {
  step: 0, revMode: "simple", monthlySales: 0,
  detailed: { seats: 0, turns: 0, avgCheck: 0, openDays: 0 },
  investment: { renovation: 0, equipment: 0, furniture: 0, deposit: 0, licenses: 0, management: 0, inventory: 0, reserve: 0 },
  invItems: { renovation: [], equipment: [], furniture: [], deposit: [], licenses: [], management: [], inventory: [], reserve: [] },
  space: { shopSqm: 0, kitchenSqm: 0 },
  foodPct: 0.32, staff: 0, rent: 0, utilities: 0, marketing: 0, management: 0, other: 0,
  costItems: { staff: [], rent: [], utilities: [], marketing: [], management: [], other: [] },
  tax: {
    vatEnabled: true, vatRate: 0.07, pricesIncludeVat: true, inputVatablePct: 0.55,
    citEnabled: true, citMode: "sme", citFlatRate: 0.20,
    ssoEnabled: true, ssoHeadcount: 0,
  },
  chart: "bar",
};

const IDEA_DEFAULTS = {
  mode: "form",
  conceptName: "", tagline: "",
  category: "", cuisine: "",
  targetCustomer: [],
  priceBand: "",
  channelMix: { dineIn: 70, delivery: 20, takeaway: 10 },
  format: { seats: 0, sqm: 0, serviceStyle: "" },
  locationType: "",
  competition: "",
  rentExpectation: 0,
  usp: "",
  founder: { experience: "", capital: 0, risk: "", involvement: "" },
  interview: { qIndex: 0, answers: {} },
  step: 0,
};

const PLAN_DEFAULTS = {
  idea: IDEA_DEFAULTS,
  market: null,
  location: { sites: [], selectedId: null },
  validation: null,
  financials: FIN_DEFAULTS,
  meta: { updatedAt: null, currency: "THB", country: "TH" },
};

function deepMerge(def, val) {
  if (val === null || val === undefined) return def;
  if (Array.isArray(def) || Array.isArray(val)) return val;
  if (typeof def === "object" && typeof val === "object") {
    const out = { ...def };
    for (const k of Object.keys(val)) out[k] = k in def ? deepMerge(def[k], val[k]) : val[k];
    return out;
  }
  return val;
}

function loadPlan() {
  try {
    const raw = localStorage.getItem(PLAN_KEY);
    if (raw) return deepMerge(PLAN_DEFAULTS, JSON.parse(raw));
  } catch (e) {}
  // migrate legacy standalone financial tool state
  try {
    const legacy = JSON.parse(localStorage.getItem("resto.v3")) || JSON.parse(localStorage.getItem("resto.v2"));
    if (legacy) {
      const { coaching, ...fin } = legacy;
      return deepMerge(PLAN_DEFAULTS, { financials: fin });
    }
  } catch (e) {}
  return JSON.parse(JSON.stringify(PLAN_DEFAULTS));
}

function usePlan() {
  const [plan, setPlan] = useState(loadPlan);
  useEffect(() => {
    try { localStorage.setItem(PLAN_KEY, JSON.stringify({ ...plan, meta: { ...plan.meta, updatedAt: new Date().toISOString() } })); } catch (e) {}
  }, [plan]);
  // setNS("idea", patch) merges patch into that namespace only
  const setNS = (ns, patch) => setPlan((p) => ({ ...p, [ns]: { ...(p[ns] || {}), ...(typeof patch === "function" ? patch(p[ns]) : patch) } }));
  const replacePlan = (next) => setPlan(deepMerge(PLAN_DEFAULTS, next));
  return { plan, setNS, replacePlan };
}

/* ============================================================
   INPUT PRIMITIVES (identical to financial tool)
   ============================================================ */
function Amount({ value, onChange, large }) {
  const [focus, setFocus] = useState(false);
  const [draft, setDraft] = useState("");
  const display = focus ? draft : value ? fmt(value) : "";
  return (
    <label style={{
      display: "flex", alignItems: "center", gap: 6, justifyContent: "flex-end",
      width: large ? "100%" : 178, padding: large ? "16px 18px" : "11px 14px",
      background: focus ? "var(--surface)" : "var(--surface-2)",
      border: `1.5px solid ${focus ? "var(--accent)" : "var(--border)"}`,
      borderRadius: 12, cursor: "text", transition: "border-color .15s, box-shadow .15s, background .15s",
      boxShadow: focus ? "0 0 0 4px var(--accent-tint)" : "none",
    }}>
      <span style={{ color: focus ? "var(--accent)" : "var(--faint)", fontWeight: 600, fontSize: large ? 22 : 16 }}>฿</span>
      <input inputMode="numeric" value={display} placeholder="0"
        onFocus={() => { setFocus(true); setDraft(value ? String(value) : ""); }}
        onBlur={() => setFocus(false)}
        onChange={(e) => { onChange(parseNum(e.target.value)); setDraft(e.target.value.replace(/[^0-9.]/g, "")); }}
        style={{ flex: 1, minWidth: 0, textAlign: "right", border: "none", outline: "none", background: "transparent", fontSize: large ? 28 : 17, fontWeight: 600, color: "var(--ink)", fontVariantNumeric: "tabular-nums", padding: 0 }} />
    </label>
  );
}

function TextInput({ value, onChange, placeholder, wide, onEnter }) {
  return (
    <input value={value} placeholder={placeholder}
      onChange={(e) => onChange(e.target.value)}
      onKeyDown={(e) => { if (e.key === "Enter" && onEnter) onEnter(); }}
      style={{
        width: wide ? "100%" : 240, padding: "12px 14px", background: "var(--surface-2)",
        border: "1.5px solid var(--border)", borderRadius: 12, fontFamily: "inherit",
        fontSize: 15, fontWeight: 500, color: "var(--ink)", outline: "none", transition: "border-color .15s, box-shadow .15s",
      }}
      onFocus={(e) => { e.target.style.borderColor = "var(--accent)"; e.target.style.boxShadow = "0 0 0 4px var(--accent-tint)"; e.target.style.background = "var(--surface)"; }}
      onBlur={(e) => { e.target.style.borderColor = "var(--border)"; e.target.style.boxShadow = "none"; e.target.style.background = "var(--surface-2)"; }} />
  );
}

function FieldRow({ label, hint, children, last, top }) {
  return (
    <div style={{ display: "flex", alignItems: top ? "flex-start" : "center", gap: 18, padding: "15px 0", borderBottom: last ? "none" : "1px solid var(--border)" }}>
      <div style={{ flex: 1, minWidth: 0, paddingTop: top ? 8 : 0 }}>
        <div style={{ fontWeight: 600, fontSize: 15.5, letterSpacing: "-.005em" }}>{label}</div>
        {hint && <div style={{ color: "var(--muted)", fontSize: 13, marginTop: 3, lineHeight: 1.4 }}>{hint}</div>}
      </div>
      <div style={{ flexShrink: 0 }}>{children}</div>
    </div>
  );
}

function Stepper({ value, onChange, min = 0, max = 9999, step = 1, suffix }) {
  const btn = (dir) => (
    <button onMouseDown={(e) => e.preventDefault()} onClick={() => onChange(Math.min(max, Math.max(min, +(value + dir * step).toFixed(2))))}
      style={{ width: 40, height: 44, border: "none", background: "transparent", cursor: "pointer", color: "var(--accent)", fontSize: 19, fontWeight: 600, display: "grid", placeItems: "center" }}>
      {dir < 0 ? "–" : "+"}
    </button>
  );
  return (
    <div style={{ display: "flex", alignItems: "center", border: "1.5px solid var(--border)", borderRadius: 12, overflow: "hidden", background: "var(--surface-2)", width: 178 }}>
      {btn(-1)}
      <div style={{ flex: 1, textAlign: "center", fontWeight: 600, fontSize: 17, fontVariantNumeric: "tabular-nums" }}>
        {value}{suffix ? <span style={{ color: "var(--muted)", fontWeight: 500, fontSize: 13 }}> {suffix}</span> : null}
      </div>
      {btn(1)}
    </div>
  );
}

function PercentSlider({ value, onChange }) {
  const pct = Math.round(value * 100);
  const inRange = pct >= 28 && pct <= 35;
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 14 }}>
        <span className="serif-fig" style={{ fontSize: 44, color: "var(--ink)", lineHeight: 1 }}>{pct}<span style={{ fontSize: 24, color: "var(--muted)" }}>%</span></span>
        <span style={{ fontSize: 12.5, color: inRange ? "var(--green)" : "var(--muted)", fontWeight: 600 }}>
          {inRange ? "✓ healthy range" : "healthy 28–35%"}
        </span>
      </div>
      <div style={{ position: "relative" }}>
        <input type="range" min="10" max="55" value={pct} onChange={(e) => onChange(parseInt(e.target.value) / 100)} style={{ width: "100%" }} />
        <div style={{ position: "absolute", left: `${((28 - 10) / 45) * 100}%`, width: `${(7 / 45) * 100}%`, top: 8, height: 6, background: "var(--green)", opacity: .25, borderRadius: 99, pointerEvents: "none" }} />
      </div>
    </div>
  );
}

function Segmented({ value, onChange, options, small }) {
  return (
    <div style={{ display: "inline-flex", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 12, padding: 4, gap: 4, flexWrap: "wrap" }}>
      {options.map((o) => {
        const active = value === o.v;
        return (
          <button key={o.v} onClick={() => onChange(o.v)} style={{
            border: "none", cursor: "pointer", borderRadius: 9, padding: small ? "7px 16px" : "10px 20px",
            fontSize: small ? 13 : 14.5, fontWeight: 600, fontFamily: "inherit", transition: "all .15s",
            background: active ? "var(--surface)" : "transparent", color: active ? "var(--accent)" : "var(--muted)",
            boxShadow: active ? "0 1px 3px rgba(20,28,40,.12)" : "none",
          }}>{o.l}</button>
        );
      })}
    </div>
  );
}

function Chips({ options, value, onChange, multi, renderLabel }) {
  const isOn = (o) => (multi ? (value || []).includes(o) : value === o);
  const toggle = (o) => {
    if (multi) {
      const cur = value || [];
      onChange(isOn(o) ? cur.filter((x) => x !== o) : [...cur, o]);
    } else onChange(isOn(o) ? "" : o);
  };
  return (
    <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
      {options.map((o) => {
        const on = isOn(o);
        return (
          <button key={o} onClick={() => toggle(o)} style={{
            border: `1.5px solid ${on ? "var(--accent)" : "var(--border)"}`,
            background: on ? "var(--accent-tint)" : "var(--surface-2)",
            color: on ? "var(--accent)" : "var(--ink)",
            borderRadius: 99, padding: "8px 16px", fontSize: 13.5, fontWeight: 600,
            fontFamily: "inherit", cursor: "pointer", transition: "all .15s",
          }}>{on ? "✓ " : ""}{renderLabel ? renderLabel(o) : o}</button>
        );
      })}
    </div>
  );
}

/* ---------- layout primitives ---------- */
const card = { background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--radius)", padding: 26, boxShadow: "var(--shadow)" };

function StepShell({ kicker, title, lead, children, k }) {
  return (
    <div key={k} style={{ animation: "fadeUp .45s cubic-bezier(.2,.7,.2,1)" }}>
      <div className="mono" style={{ fontSize: 11.5, letterSpacing: ".14em", textTransform: "uppercase", color: "var(--brass-deep)", fontWeight: 600, display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ width: 16, height: 1.5, background: "var(--brass)" }} />{kicker}
      </div>
      <h1 className="serif" style={{ fontSize: 42, fontWeight: 400, margin: "16px 0 10px", letterSpacing: "-.015em", lineHeight: 1.05, color: "var(--ink)" }}>{title}</h1>
      <p style={{ fontSize: 16.5, color: "var(--muted)", margin: "0 0 26px", maxWidth: 520, lineHeight: 1.55 }}>{lead}</p>
      {children}
    </div>
  );
}

function Tip({ children }) {
  return (
    <div style={{ marginTop: 16, display: "flex", gap: 13, padding: "15px 18px", background: "var(--accent-tint)", borderRadius: 14, alignItems: "flex-start" }}>
      <span style={{ width: 20, height: 20, borderRadius: 6, background: "var(--accent)", color: "#fff", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 12, flexShrink: 0, marginTop: 1, fontStyle: "italic", fontFamily: "Newsreader, serif" }}>i</span>
      <span style={{ fontSize: 14.5, lineHeight: 1.55, color: "var(--ink)" }}>{children}</span>
    </div>
  );
}

const TotalRow = ({ label, value, tone }) => (
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", paddingTop: 20, marginTop: 4 }}>
    <span style={{ fontWeight: 600, fontSize: 16 }}>{label}</span>
    <span className="serif-fig" style={{ fontSize: 30, color: tone || "var(--navy)" }}>{value}</span>
  </div>
);

function Flag({ tone, text }) {
  const c = toneVar(tone, "fg"), bg = toneVar(tone, "bg");
  const mark = tone === "green" ? "✓" : tone === "red" ? "!" : "›";
  return (
    <div style={{ display: "flex", gap: 13, alignItems: "flex-start" }}>
      <span style={{ width: 22, height: 22, borderRadius: 7, background: bg, color: c, fontWeight: 800, display: "grid", placeItems: "center", flexShrink: 0, fontSize: 13, marginTop: 1 }}>{mark}</span>
      <span style={{ fontSize: 14.5, lineHeight: 1.55, color: "var(--ink)" }}>{text}</span>
    </div>
  );
}

function Stat({ label, value, sub, tone }) {
  const fg = tone === "green" ? "var(--green)" : tone === "red" ? "var(--red)" : tone === "amber" ? "var(--amber)" : "var(--ink)";
  return (
    <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 16, padding: "18px 20px", boxShadow: "var(--shadow)" }}>
      <div className="mono" style={{ fontSize: 10.5, letterSpacing: ".09em", textTransform: "uppercase", color: "var(--muted)" }}>{label}</div>
      <div className="serif-fig" style={{ fontSize: 32, marginTop: 8, color: fg, whiteSpace: "nowrap", lineHeight: 1.05 }}>{value}</div>
      {sub && <div style={{ fontSize: 12.5, color: "var(--muted)", marginTop: 5 }}>{sub}</div>}
    </div>
  );
}

/* source/confidence label — the "estimate vs your input vs benchmark" pattern */
function SourceTag({ kind, confidence }) {
  const { t } = useLang();
  const label = kind === "input" ? t("common.yourInput") : kind === "benchmark" ? t("common.benchmark") : t("common.estimate");
  const conf = confidence === "low" ? t("common.low") : confidence;
  return (
    <span className="mono" style={{ fontSize: 9, letterSpacing: ".08em", textTransform: "uppercase", color: "var(--faint)", border: "1px solid var(--border)", borderRadius: 6, padding: "2px 7px", whiteSpace: "nowrap" }}>
      {label}{conf ? ` · ${conf}` : ""}
    </span>
  );
}

/* round "!" info marker with hover/focus tooltip — Thai tax explainers etc. */
function InfoDot({ text }) {
  const [open, setOpen] = useState(false);
  const [flip, setFlip] = useState({ x: false, y: false });
  const ref = useRef(null);
  const show = () => {
    const r = ref.current ? ref.current.getBoundingClientRect() : { left: 0, bottom: 0 };
    setFlip({ x: r.left > window.innerWidth - 330, y: r.bottom > window.innerHeight - 230 });
    setOpen(true);
  };
  const tipStyle = {
    position: "absolute", zIndex: 60, width: 300, maxWidth: "78vw",
    background: "var(--surface)", border: "1px solid var(--border)", boxShadow: "var(--shadow-lg)",
    borderRadius: 12, padding: "12px 14px", fontSize: 12.5, lineHeight: 1.5, color: "var(--ink)",
    fontWeight: 400, fontStyle: "normal", fontFamily: "'Hanken Grotesk',system-ui,sans-serif",
    textAlign: "left", display: "block", whiteSpace: "normal", animation: "fadeIn .15s",
  };
  tipStyle[flip.y ? "bottom" : "top"] = "calc(100% + 8px)";
  tipStyle[flip.x ? "right" : "left"] = -8;
  return (
    <span ref={ref} style={{ position: "relative", display: "inline-flex", verticalAlign: "middle" }}
      onMouseEnter={show} onMouseLeave={() => setOpen(false)}>
      <button type="button" aria-label="How this is estimated" onFocus={show} onBlur={() => setOpen(false)}
        style={{ width: 17, height: 17, borderRadius: "50%", border: "1.5px solid var(--brass)", background: "transparent", color: "var(--brass-deep)", fontSize: 11, fontWeight: 700, fontStyle: "italic", fontFamily: "Newsreader, serif", display: "grid", placeItems: "center", cursor: "help", padding: 0, lineHeight: 1 }}>!</button>
      {open && <span role="tooltip" style={tipStyle}>{text}</span>}
    </span>
  );
}

const btnPrimary = { border: "none", cursor: "pointer", borderRadius: 13, padding: "14px 28px", fontSize: 15.5, fontWeight: 700, fontFamily: "inherit", background: "var(--accent)", color: "#fff", boxShadow: "0 1px 2px rgba(27,59,95,.3), 0 10px 24px -10px rgba(27,59,95,.55)", transition: "transform .12s, filter .12s" };
const btnGhost = { border: "1.5px solid var(--border-strong)", cursor: "pointer", borderRadius: 13, padding: "14px 26px", fontSize: 15.5, fontWeight: 600, fontFamily: "inherit", background: "var(--surface)", color: "var(--ink)" };

/* ============================================================
   IMPORT / EXPORT PANEL
   ============================================================ */
function ImportExport({ plan, replacePlan, onClose }) {
  const { t } = useLang();
  const [text, setText] = useState("");
  const [msg, setMsg] = useState(null);
  const json = JSON.stringify(plan, null, 2);
  const download = () => {
    const blob = new Blob([json], { type: "application/json" });
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = "resto-plan.json";
    a.click();
    URL.revokeObjectURL(a.href);
  };
  const applyText = (raw) => {
    try {
      const obj = JSON.parse(raw);
      if (typeof obj !== "object" || !obj) throw new Error();
      replacePlan(obj);
      setMsg({ tone: "green", text: t("ie.imported") });
    } catch (e) { setMsg({ tone: "red", text: t("ie.invalidJson") }); }
  };
  const onFile = (e) => {
    const f = e.target.files[0]; if (!f) return;
    const r = new FileReader();
    r.onload = () => applyText(r.result);
    r.readAsText(f);
  };
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(17,32,58,.5)", zIndex: 100, display: "grid", placeItems: "center", padding: 20, animation: "fadeIn .2s" }}>
      <div onClick={(e) => e.stopPropagation()} style={{ ...card, width: "min(560px, 100%)", maxHeight: "85vh", overflowY: "auto", padding: 30 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <h2 className="serif" style={{ fontSize: 26, fontWeight: 400, margin: 0 }}>{t("ie.title")}</h2>
            <div style={{ color: "var(--muted)", fontSize: 13.5, marginTop: 5, lineHeight: 1.5 }}>{t("ie.desc")}</div>
          </div>
          <button onClick={onClose} style={{ border: "none", background: "var(--surface-2)", borderRadius: 9, width: 32, height: 32, cursor: "pointer", fontSize: 16, color: "var(--muted)" }}>×</button>
        </div>
        <div style={{ display: "flex", gap: 10, marginTop: 20 }}>
          <button onClick={download} style={{ ...btnPrimary, padding: "12px 20px", fontSize: 14 }}>{t("ie.download")}</button>
          <button onClick={() => { navigator.clipboard && navigator.clipboard.writeText(json); setMsg({ tone: "green", text: t("ie.copied") }); }} style={{ ...btnGhost, padding: "12px 20px", fontSize: 14 }}>{t("ie.copy")}</button>
        </div>
        <div style={{ marginTop: 24, paddingTop: 20, borderTop: "1px solid var(--border)" }}>
          <div style={{ fontWeight: 600, fontSize: 14.5 }}>{t("ie.importHeading")}</div>
          <div style={{ color: "var(--muted)", fontSize: 13, marginTop: 3 }}>{t("ie.importDesc")}</div>
          <input type="file" accept=".json,application/json" onChange={onFile} style={{ marginTop: 12, fontSize: 13.5, fontFamily: "inherit" }} />
          <textarea value={text} onChange={(e) => setText(e.target.value)} placeholder='{"idea": … }' rows={5}
            style={{ width: "100%", marginTop: 12, padding: 12, borderRadius: 12, border: "1.5px solid var(--border)", background: "var(--surface-2)", fontFamily: "'JetBrains Mono', monospace", fontSize: 12, resize: "vertical", outline: "none", boxSizing: "border-box" }} />
          <button onClick={() => applyText(text)} disabled={!text.trim()} style={{ ...btnGhost, padding: "10px 18px", fontSize: 13.5, marginTop: 10, opacity: text.trim() ? 1 : .5 }}>{t("ie.applyPasted")}</button>
        </div>
        {msg && <div style={{ marginTop: 14 }}><Flag tone={msg.tone} text={msg.text} /></div>}
      </div>
    </div>
  );
}

Object.assign(window, {
  fmt, fmtBaht, fmtPct, fmtMonths, parseNum, money, toneVar, useMedia,
  PLAN_KEY, PLAN_DEFAULTS, FIN_DEFAULTS, IDEA_DEFAULTS, deepMerge, loadPlan, usePlan,
  Amount, TextInput, FieldRow, Stepper, PercentSlider, Segmented, Chips,
  card, StepShell, Tip, TotalRow, Flag, Stat, SourceTag, InfoDot, btnPrimary, btnGhost,
  ImportExport,
});
