// app.jsx — main state machine, theming, render.
const { useState: useS, useEffect: useE } = React;

// 상담 접수 백엔드 (biz.anyinsu.com, GnuBoard4 anyinsu_classic). CORS 허용됨.
const CONSULT_API = "https://biz.anyinsu.com/anyinsu/api.php";

const THEMES = {
  navy:   { label: "딥 네이비", v: { "--bg":"#03070f","--app-bg":"#0a1a30","--app-bg-2":"#06101f","--surface":"#102844","--surface-2":"#16314f","--surface-hi":"#1c3a5e","--border":"rgba(255,255,255,.09)","--border-hi":"rgba(255,255,255,.16)","--text":"#eef4fb","--text-muted":"#9fb1c9","--text-dim":"#6f86a3","--accent":"#2fe0c0","--accent-ink":"#042018","--accent-soft":"rgba(47,224,192,.12)","--accent-line":"rgba(47,224,192,.35)","--accent-glow":"rgba(47,224,192,.5)" } },
  indigo: { label: "인디고", v: { "--bg":"#05060f","--app-bg":"#0e1330","--app-bg-2":"#080a1c","--surface":"#181d3e","--surface-2":"#22284f","--surface-hi":"#2b3360","--border":"rgba(255,255,255,.09)","--border-hi":"rgba(255,255,255,.16)","--text":"#eef1fb","--text-muted":"#a6acce","--text-dim":"#737aa3","--accent":"#5fa8ff","--accent-ink":"#04122b","--accent-soft":"rgba(95,168,255,.14)","--accent-line":"rgba(95,168,255,.4)","--accent-glow":"rgba(95,168,255,.5)" } },
  violet: { label: "미드나잇", v: { "--bg":"#06040d","--app-bg":"#15102e","--app-bg-2":"#0c0820","--surface":"#221a44","--surface-2":"#2d2356","--surface-hi":"#382c66","--border":"rgba(255,255,255,.09)","--border-hi":"rgba(255,255,255,.17)","--text":"#f1edfb","--text-muted":"#b6abd4","--text-dim":"#7e72a0","--accent":"#a98bff","--accent-ink":"#190a33","--accent-soft":"rgba(169,139,255,.16)","--accent-line":"rgba(169,139,255,.4)","--accent-glow":"rgba(169,139,255,.5)" } },
  light:  { label: "클린 라이트", v: { "--bg":"#e7ecf3","--app-bg":"#f6f8fc","--app-bg-2":"#eef2f8","--surface":"#ffffff","--surface-2":"#f1f5fb","--surface-hi":"#e8eef6","--border":"rgba(15,32,60,.10)","--border-hi":"rgba(15,32,60,.2)","--text":"#0f1f38","--text-muted":"#5a6b86","--text-dim":"#94a3b8","--accent":"#0fb89a","--accent-ink":"#ffffff","--accent-soft":"rgba(15,184,154,.10)","--accent-line":"rgba(15,184,154,.4)","--accent-glow":"rgba(15,184,154,.4)" } },
};
const THEME_LABELS = Object.keys(THEMES).map((k) => THEMES[k].label);
const LABEL_TO_KEY = Object.fromEntries(Object.keys(THEMES).map((k) => [THEMES[k].label, k]));

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "딥 네이비",
  "radius": 18
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const themeKey = LABEL_TO_KEY[t.theme] || "navy";

  useE(() => {
    const root = document.documentElement;
    const vars = THEMES[themeKey].v;
    Object.keys(vars).forEach((k) => root.style.setProperty(k, vars[k]));
    root.style.setProperty("--radius", t.radius + "px");
    root.style.setProperty("--radius-sm", Math.max(8, t.radius - 5) + "px");
  }, [themeKey, t.radius]);

  // ---- flow state ----
  const [screen, setScreen] = useS("home");
  const [overlay, setOverlay] = useS(null); // {title, sub} | null
  const [name, setName] = useS("");
  const [phone, setPhone] = useS("");
  const [industry, setIndustry] = useS("");
  const [pyeong, setPyeong] = useS("");
  const [result, setResult] = useS(null);
  const [liabChoice, setLiabChoice] = useS("");
  const [summary, setSummary] = useS("");
  const [consultId, setConsultId] = useS(null);     // 접수 후 발급된 레코드 id
  const [consultToken, setConsultToken] = useS("");  // 사업자등록증 업로드 인증 토큰

  const goTop = () => { const b = document.querySelector(".screen-body"); if (b) b.scrollTop = 0; };

  // 화면 전환을 브라우저 히스토리에 기록 → 모바일/브라우저 '뒤로가기'가 사이트를 벗어나지 않고
  // 직전 단계로 이동하도록 함. (home 진입점에서만 뒤로가기 시 사이트 이탈 허용)
  const go = (s) => {
    window.history.pushState({ screen: s }, "");
    setScreen(s);
    requestAnimationFrame(goTop);
  };
  const goBack = () => window.history.back();

  useE(() => {
    // 최초 진입(home)을 히스토리 baseline 으로 기록
    window.history.replaceState({ screen: "home" }, "");
    const onPop = (e) => {
      const s = (e.state && e.state.screen) || "home";
      setOverlay(null);
      setScreen(s);
      requestAnimationFrame(goTop);
    };
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, []);

  const reset = () => {
    setName(""); setPhone(""); setIndustry(""); setPyeong("");
    setResult(null); setLiabChoice(""); setSummary("");
    setConsultId(null); setConsultToken(""); go("home");
  };

  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

  // [선접수] 보험 선택 화면 진입 시점에 이름·전화로 상담 행을 먼저 생성(status=진행중).
  // 이후 단계는 같은 행을 Update. (이미 접수된 경우 중복 생성 방지)
  const startConsult = async (force) => {
    if (consultId && !force) return;   // force=true: 재인증 시 새 접수 행 강제 생성
    try {
      const res = await fetch(CONSULT_API + "?action=start", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, phone }),
      });
      const j = await res.json();
      if (j && j.ok) { setConsultId(j.id); setConsultToken(j.token); }
    } catch (e) { /* noop */ }
  };

  // [최종 제출] 선접수 행이 있으면 Update, 없으면(네트워크 실패 등) create 로 fallback.
  // 네트워크 실패해도 완료 화면은 정상 노출(접수 자체는 담당자 연락으로 진행).
  const finalizeConsult = async (payload, sm, overlayMsg) => {
    setSummary(sm);
    setOverlay(overlayMsg);
    try {
      if (consultId) {
        await fetch(CONSULT_API + "?action=update", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ id: consultId, token: consultToken, ...payload, summary: sm, step: "done" }),
        });
      } else {
        const res = await fetch(CONSULT_API + "?action=create", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ ...payload, summary: sm }),
        });
        const j = await res.json();
        if (j && j.ok) { setConsultId(j.id); setConsultToken(j.token); }
      }
    } catch (e) { /* noop — 완료 화면은 그대로 진행 */ }
    await sleep(700);
    setOverlay(null); go("done");
  };

  // 완료 화면에서 사업자등록증 업로드 (consultId 발급된 경우에만).
  const uploadBizCert = async (file) => {
    if (!consultId) return { ok: false, error: "no-id" };
    const fd = new FormData();
    fd.append("action", "upload");
    fd.append("id", consultId);
    fd.append("token", consultToken);
    fd.append("file", file);
    try {
      const res = await fetch(CONSULT_API, { method: "POST", body: fd });
      return await res.json();
    } catch (e) { return { ok: false, error: "network" }; }
  };

  const handleVerify = () => {
    setOverlay({ title: "본인확인을 진행하고 있어요", sub: "외부 인증기관을 통해 본인 여부를 확인합니다." });
    setTimeout(() => {
      setOverlay(null); go("type");
      // 뒤로가기 후 재인증 시에도 새 접수 행이 생성되도록 이전 접수 id 초기화 + 강제 생성
      setConsultId(null); setConsultToken("");
      startConsult(true);
    }, 1800);
  };

  // 화재보험 안내내용(guide) 빌더 — 산출 결과 + 근거(실제/로컬/null similar 모두 대응)
  const buildFireGuide = (r) => {
    const won = (n) => (n || n === 0) ? Number(n).toLocaleString("ko-KR") : "-";
    const lines = [];
    const basisNote = (r.premiumBasis === "similar" && r.similar)
      ? ` (유사 청약 #${r.similar.id != null ? r.similar.id : "-"} 확인 보험료 그대로 적용)`
      : " (업종·면적 추정)";
    lines.push(`[예상 보험료] 월 ${won(r.monthly)}원 · 연납 ${won(r.yearly)}원${basisNote}`);
    lines.push(`[산출 조건] ${r.industryLabel || r.industry.name} · ${r.pyeong}평${r.m2 ? `(약 ${Math.round(r.m2)}㎡)` : ""}`);
    if (r.coverage) lines.push(`[보장 한도] 화재·재산 ${r.coverage.fire} / 배상책임 ${r.coverage.liab}`);
    if (r.similar && r.similar.real) {
      // 실제 등록 청약서 기반 근거 — 청약서 ID + 연보험료 + 상세 정보
      const s = r.similar;
      lines.push(`[근거] 유사 계약(실제 등록 청약서 #${s.id != null ? s.id : "-"})`);
      lines.push(`- 업종: ${s.industryName || "-"}`);
      const areaTxt = (s.m2 != null && s.m2 !== "") ? `${won(Math.round(s.m2))}㎡${s.pyeong ? ` (약 ${s.pyeong}평)` : ""}` : (s.pyeong ? `${s.pyeong}평` : "-");
      lines.push(`- 사업장면적: ${areaTxt}`);
      lines.push(`- 연 보험료: ${s.yearly != null ? `${won(s.yearly)}원` : "-"}${s.monthly != null ? ` (월 ${won(s.monthly)}원)` : ""}`);
      if (s.coverage != null && s.coverage !== "") lines.push(`- 총보험가입금액: ${won(s.coverage)}원`);
      if (s.applyDate) lines.push(`- 청약일: ${s.applyDate}`);
    } else if (r.similar) {
      // (폴백) 로컬 추정 유사 계약 — 한 줄
      const s = r.similar;
      const when = s.applyDate ? s.applyDate : (s.months != null ? `${s.months}개월 전 청약` : "");
      const price = (s.yearly != null) ? `연 ${won(s.yearly)}원` : (s.monthly != null ? `${won(s.monthly)}원/월` : "");
      lines.push(`[근거] 유사 계약 — ${s.region ? s.region + " · " : ""}${s.industryName || ""}${s.pyeong ? " " + s.pyeong + "평" : ""}${price ? ", " + price : ""}${when ? " (" + when + ")" : ""}`);
    } else {
      lines.push(`[근거] 유사 계약 데이터 없음`);
    }
    return lines.join("\n");
  };
  const fireIndustry = (r) => r.industryLabel || (r.industry && r.industry.name) || "";
  const fireSummary = (r) => `화재보험 · ${fireIndustry(r)} ${r.pyeong}평 설계사 상담`;
  const fireDetail  = (r) => ({ 업종: fireIndustry(r), 평수: `${r.pyeong}평` });

  // [2단계] 보험료 산출 결과 시점에 상담내용+안내내용 업데이트 (status=보험료확인)
  const submitEstimate = async (r) => {
    if (!consultId) return;
    try {
      await fetch(CONSULT_API + "?action=estimate", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id: consultId, token: consultToken, type: "fire", summary: fireSummary(r), detail: fireDetail(r), guide: buildFireGuide(r) }),
      });
    } catch (e) { /* noop */ }
  };

  const handleFireSubmit = async (customIndustry) => {
    setOverlay({ title: "AI가 분석하고 있어요", sub: "업종·면적 조건으로 유사 계약을 찾는 중입니다." });
    const base = estimateFire(industry, Number(pyeong));   // 예상 보험료(로컬 추정)
    const ind = INDUSTRIES.find((i) => i.id === industry) || {};
    // 기타 업종이면 상세 업종 입력값을 유효 업종명으로 사용(상담내용·안내내용·표시에 반영)
    base.industryLabel = (industry === "etc" && customIndustry && customIndustry.trim())
      ? customIndustry.trim()
      : (ind.name || (base.industry && base.industry.name) || "");
    try {
      const res = await fetch(CONSULT_API + "?action=similar", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          industryId: industry, industryName: ind.name || "",
          customIndustry: customIndustry || "", pyeong: Number(pyeong),
        }),
      });
      const j = await res.json();
      base.similar = (j && j.ok && j.result) ? {
        real: true,
        id: j.result.id,
        industryName: j.result.industry,
        pyeong: j.result.pyeong,
        m2: j.result.site_area,
        yearly: j.result.annual_premium,
        monthly: j.result.annual_premium ? Math.round(j.result.annual_premium / 12) : null,
        coverage: j.result.total_coverage,
        applyDate: j.result.apply_date,
      } : null;
    } catch (e) {
      base.similar = null;
    }
    // 예상 보험료: 유사 청약건(실제)이 있으면 그 확인 보험료를 보정 없이 그대로 산출 보험료로 제시.
    //  유사건이 없으면 추정공식 값을 사용.
    base.premiumBasis = "estimate";
    if (base.similar && base.similar.real && base.similar.yearly > 0) {
      base.yearly  = base.similar.yearly;
      base.monthly = (base.similar.monthly != null) ? base.similar.monthly : Math.round(base.similar.yearly / 12);
      base.premiumBasis = "similar";
    }
    // 분석 연출 시간 보장(최소 1.2s)
    await new Promise((r) => setTimeout(r, 1200));
    setResult(base);
    submitEstimate(base);            // [2단계] 상담내용/안내내용 + status=보험료확인
    setOverlay(null); go("fireResult");
  };

  // [3단계] 상담 접수(상담신청) — 고객 메모는 cust_memo 로 분리 저장. content/guide 는 2단계(estimate)에서 설정됨.
  const handleConsult = (memo) => {
    const r = result;
    const memoText = memo ? ` · 메모: ${memo}` : "";
    const sm = fireSummary(r) + memoText;   // done 화면 표시용
    finalizeConsult(
      // 정상 경로: estimate 가 content/guide 설정 → 여기선 cust_memo + status 만. (no-id 폴백 대비 입력값도 함께 전송)
      { type: "fire", name, phone, cust_memo: memo || "", summary: fireSummary(r), detail: fireDetail(r), guide: buildFireGuide(r) },
      sm,
      { title: "상담 신청을 접수하고 있어요", sub: "잠시만 기다려 주세요." }
    );
  };

  const handleLiabSubmit = () => {
    const opt = LIAB_OPTIONS.find((o) => o.id === liabChoice);
    const sm = `영업배상책임보험 · ${opt.title}`;
    finalizeConsult(
      { type: "liability", name, phone, detail: { 요청유형: opt.title, 설명: opt.desc } },
      sm,
      { title: "산출 의뢰를 접수하고 있어요", sub: "담당자에게 요청을 전달합니다." }
    );
  };

  const handleConsultReq = () => {
    finalizeConsult(
      { type: "consult", name, phone, detail: {} },
      "보험 상담 요청",
      { title: "상담 요청을 접수하고 있어요", sub: "담당 상담사에게 요청을 전달합니다." }
    );
  };

  let view = null;
  if (screen === "home") view = <Home onStart={() => go("verify")} />;
  else if (screen === "verify") view = <Verify name={name} setName={setName} phone={phone} setPhone={setPhone} onVerify={handleVerify} onBack={goBack} />;
  else if (screen === "type") view = <SelectType name={name} onSelect={(ty) => go(ty === "fire" ? "fireForm" : "liability")} onConsult={handleConsultReq} onBack={goBack} />;
  else if (screen === "fireForm") view = <FireForm industry={industry} setIndustry={setIndustry} pyeong={pyeong} setPyeong={setPyeong} onSubmit={handleFireSubmit} onBack={goBack} />;
  else if (screen === "liability") view = <LiabilityForm choice={liabChoice} setChoice={setLiabChoice} onSubmit={handleLiabSubmit} onBack={goBack} />;
  else if (screen === "fireResult") view = <FireResult result={result} name={name} onConsult={handleConsult} onRedo={goBack} onBack={goBack} />;
  else if (screen === "done") view = <Done name={name} phone={phone} summary={summary} onHome={reset} canUpload={!!consultId} onUpload={uploadBizCert} />;

  return (
    <div className="app">
      <div key={screen} style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>{view}</div>
      {overlay && <Overlay title={overlay.title} sub={overlay.sub} />}
      <TweaksPanel>
        <TweakSection label="테마" />
        <TweakSelect label="컬러 테마" value={t.theme} options={THEME_LABELS} onChange={(v) => setTweak("theme", v)} />
        <TweakSlider label="모서리 둥글기" value={t.radius} min={8} max={26} step={1} unit="px" onChange={(v) => setTweak("radius", v)} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
