/* global React, Icons, AI, AutoText, Field, Section, AIBulletBtn, ResumePaper, PagedPaper, ExportControls, ExportButton, Pro, useProState, resumeToText, isProTemplate */
// ============================================================
//  Builder — editable form (left) + live preview (right)
// ============================================================

function uid() { return Math.random().toString(36).slice(2, 9); }

// Apply an inline-edit (from clicking text on the résumé) back into the résumé
// data. Path grammar:
//   "name" | "summary" | "email" | …            top-level scalar
//   "skills:<index>:name"                         skill name (keeps its level)
//   "<section>:<index>"                           chips array of strings
//   "experience:<id>:role|company|location"       keyed object field
//   "experience:<id>:bullet:<index>"              one bullet
//   "education:<id>:school|degree", "projects:<id>:name|desc", etc.
function setByPath(d, path, val) {
  const p = path.split(":");
  if (p.length === 1) { d[p[0]] = val; return; }
  const sec = p[0];
  const arr = d[sec];
  if (!Array.isArray(arr)) return;
  if (p.length === 2) {                                  // chips: section:index
    const i = Number(p[1]);
    if (Number.isInteger(i)) d[sec] = arr.map((s, j) => (j === i ? val : s));
    return;
  }
  if (sec === "skills") {                                // skills:index:name
    const i = Number(p[1]);
    d.skills = arr.map((s, j) => (j === i ? (s && typeof s === "object" ? { ...s, name: val } : val) : s));
    return;
  }
  const id = p[1], field = p[2];
  d[sec] = arr.map((it) => {
    if (!it || it.id !== id) return it;
    if (field === "bullet") {
      const bi = Number(p[3]);
      return { ...it, bullets: (it.bullets || []).map((b, j) => (j === bi ? val : b)) };
    }
    return { ...it, [field]: val };
  });
}

function Toast({ msg }) {
  if (!msg) return null;
  return <div className="toast glass"><Icons.spark size={14} style={{ color: "var(--acc)" }} /> {msg}</div>;
}

// ---- résumé strength score (a whole-résumé "scale") ----------------------
function scoreResume(d) {
  const checks = [];
  const txt = (v) => v && String(v).trim();
  const contactN = ["email", "phone", "location", "website"].filter((k) => txt(d[k])).length;
  checks.push({ key: "basics", label: "Contact details", got: Math.min(contactN, 3), max: 3, weight: 11, hint: "Add email, phone & location" });
  checks.push({ key: "title", label: "Headline", got: txt(d.title) ? 1 : 0, max: 1, weight: 6, hint: "Add a target-role headline" });
  checks.push({ key: "summary", label: "Summary", got: (txt(d.summary) || "").length > 50 ? 1 : 0, max: 1, weight: 14, hint: "Write a 2–3 line summary" });
  const exp = d.experience || [];
  const bulletN = exp.reduce((n, e) => n + (e.bullets || []).filter((b) => txt(b)).length, 0);
  const quantN = exp.reduce((n, e) => n + (e.bullets || []).filter((b) => /\d/.test(b || "")).length, 0);
  checks.push({ key: "exp", label: "Experience", got: Math.min(exp.length, 2), max: 2, weight: 18, hint: "Add at least 2 roles" });
  checks.push({ key: "bullets", label: "Impact bullets", got: Math.min(bulletN, 4), max: 4, weight: 15, hint: "Write 4+ achievement bullets" });
  checks.push({ key: "quant", label: "Quantified results", got: Math.min(quantN, 2), max: 2, weight: 11, hint: "Add metrics (%, $, #) to bullets" });
  checks.push({ key: "skills", label: "Rated skills", got: Math.min((d.skills || []).length, 6), max: 6, weight: 9, hint: "List 6+ skills with levels" });
  checks.push({ key: "edu", label: "Education", got: (d.education || []).length ? 1 : 0, max: 1, weight: 6, hint: "Add your education" });
  const totalW = checks.reduce((s, c) => s + c.weight, 0);
  const got = checks.reduce((s, c) => s + c.weight * Math.min(1, c.got / c.max), 0);
  return { score: Math.round((got / totalW) * 100), checks };
}
const scoreBand = (s) => (s >= 85 ? "Excellent" : s >= 68 ? "Strong" : s >= 45 ? "Good" : "Needs work");

function ScoreRing({ score }) {
  const R = 14, C = 2 * Math.PI * R;
  return (
    <svg width="34" height="34" viewBox="0 0 34 34">
      <circle cx="17" cy="17" r={R} fill="none" stroke="var(--line)" strokeWidth="3.2" />
      <circle cx="17" cy="17" r={R} fill="none" stroke="url(#scoreg)" strokeWidth="3.2" strokeLinecap="round"
        strokeDasharray={C} strokeDashoffset={C * (1 - score / 100)} transform="rotate(-90 17 17)" style={{ transition: "stroke-dashoffset 0.5s ease" }} />
      <defs><linearGradient id="scoreg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="var(--acc)" /><stop offset="1" stopColor="var(--acc-2)" /></linearGradient></defs>
    </svg>
  );
}

function ResumeScore({ resume }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h);
  }, []);
  const { score, checks } = scoreResume(resume);
  const todo = checks.filter((c) => c.got < c.max).length;
  return (
    <div className="score-wrap" ref={ref}>
      <button className={`score-chip ${open ? "on" : ""}`} onClick={() => setOpen((o) => !o)} title="Résumé strength">
        <span className="score-ring"><ScoreRing score={score} /><b>{score}</b></span>
        <span className="score-txt"><span className="score-band">{scoreBand(score)}</span><span className="score-sub">Strength</span></span>
      </button>
      {open && (
        <div className="score-pop glass">
          <div className="score-pop-h">
            <div><b>Résumé strength</b><span className="score-pop-band">{scoreBand(score)} · {score}/100</span></div>
            <span className="score-pop-ring"><ScoreRing score={score} /><b>{score}</b></span>
          </div>
          <div className="score-pop-list">
            {checks.map((c) => {
              const done = c.got >= c.max;
              return (
                <div className={`score-row ${done ? "done" : ""}`} key={c.key}>
                  <span className="score-check">{done ? <Icons.check size={12} /> : null}</span>
                  <span className="score-row-l">{c.label}{!done && <em>{c.hint}</em>}</span>
                  <span className="score-row-n">{c.got}/{c.max}</span>
                </div>
              );
            })}
          </div>
          <div className="score-pop-foot">{todo === 0 ? "Looking sharp — every box checked." : `${todo} ${todo === 1 ? "thing" : "things"} left to strengthen your résumé.`}</div>
        </div>
      )}
    </div>
  );
}

function Builder({ resume, setResume, templateId, setTemplateId, accent, setAccent, layout, skillStyle, onGallery, onCoverStudio }) {
  const tpls = window.TEMPLATES;
  const tpl = tpls.find((t) => t.id === templateId) || tpls[0];
  const { isPro, aiRemaining } = useProState();
  const [busy, setBusy] = useState({});      // keyed loading flags
  const [toast, setToast] = useState("");
  const [zoom, setZoom] = useState(1);
  const [paperH, setPaperH] = useState(1000);
  const stageRef = useRef(null);
  const innerRef = useRef(null);
  const editingRef = useRef(false);   // true while an inline edit is focused

  const flash = (m) => { setToast(m); setTimeout(() => setToast(""), 2600); };

  // ---- inline editing on the paper + click-to-locate the form section ----
  const commitInline = (path, val) => {
    setResume((r) => { const d = JSON.parse(JSON.stringify(r)); setByPath(d, path, val); return d; });
  };
  const onPreviewMouseDown = (e) => {
    // only act on the visible page content (never the offscreen measuring copy)
    if (!e.target.closest(".pg-clip")) return;
    // 1) light up the form section that controls whatever was clicked
    const idEl = e.target.closest(".rid");
    const secEl = e.target.closest("[data-sec]");
    const key = idEl ? "basics" : (secEl ? secEl.getAttribute("data-sec") : null);
    if (key) window.dispatchEvent(new CustomEvent("rb-focus-section", { detail: { key } }));
    // 2) make the clicked text directly editable in place
    const ed = e.target.closest("[data-edit]");
    if (!ed || ed.getAttribute("contenteditable") === "true") return;
    const path = ed.getAttribute("data-edit");
    const orig = ed.textContent;
    const multi = path === "summary" || /:bullet:/.test(path);
    ed.setAttribute("contenteditable", "true");
    ed.classList.add("rb-edit-on");
    editingRef.current = true;
    const finish = () => {
      ed.removeEventListener("blur", finish);
      ed.removeEventListener("keydown", onKey);
      ed.removeAttribute("contenteditable");
      ed.classList.remove("rb-edit-on");
      editingRef.current = false;
      const val = ed.textContent.replace(/\u00a0/g, " ").replace(/[ \t]+/g, " ").trim();
      if (val !== orig.trim()) commitInline(path, val);
    };
    const onKey = (ev) => {
      if (ev.key === "Enter" && !(multi && ev.shiftKey)) { ev.preventDefault(); ed.blur(); }
      else if (ev.key === "Escape") { ev.preventDefault(); ed.textContent = orig; ed.blur(); }
    };
    ed.addEventListener("blur", finish);
    ed.addEventListener("keydown", onKey);
    // let the browser place the caret from this same mousedown (no preventDefault)
  };

  // accent for the resume: follow template unless user overrode
  const pa = accent.custom ? accent : { a: tpl.accent, b: tpl.accent2 };

  // ---- fit preview to stage ----
  useEffect(() => {
    const fit = () => {
      const stage = stageRef.current; if (!stage) return;
      const pad = 56;
      const avail = stage.clientWidth - pad;
      const s = Math.min(0.95, Math.max(0.3, avail / 768));
      setZoom(s);
    };
    fit();
    const ro = new ResizeObserver(fit);
    if (stageRef.current) ro.observe(stageRef.current);
    return () => ro.disconnect();
  }, [layout]);

  // ---- measure natural paper height to size the scaled wrapper ----
  useEffect(() => {
    const el = innerRef.current; if (!el) return;
    const measure = () => { if (editingRef.current) return; setPaperH(el.offsetHeight || 1000); };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    return () => ro.disconnect();
  }, [templateId, resume]);

  // ---- update helpers ----
  const set = (patch) => setResume((r) => ({ ...r, ...patch }));
  const setExp = (id, patch) => set({ experience: resume.experience.map((e) => e.id === id ? { ...e, ...patch } : e) });
  const setBullet = (eid, idx, val) => setExp(eid, { bullets: resume.experience.find((e) => e.id === eid).bullets.map((b, i) => i === idx ? val : b) });

  // ---- AI actions ----
  const aiBullet = async (eid, idx, mode) => {
    if (!Pro.guardAI()) return;
    const exp = resume.experience.find((e) => e.id === eid);
    const key = `b-${eid}-${idx}`;
    setBusy((b) => ({ ...b, [key]: true }));
    const out = await AI.rewriteBullet(exp.bullets[idx], exp.role, mode);
    setBusy((b) => ({ ...b, [key]: false }));
    if (out) { setBullet(eid, idx, out); Pro.recordAI(); flash("Bullet rewritten with AI"); }
    else flash("Couldn't reach AI — try again");
  };

  const aiSummary = async () => {
    if (!Pro.guardAI()) return;
    setBusy((b) => ({ ...b, summary: true }));
    const out = await AI.writeSummary(resume);
    setBusy((b) => ({ ...b, summary: false }));
    if (out) { set({ summary: out }); Pro.recordAI(); flash("Summary generated"); }
    else flash("Couldn't reach AI — try again");
  };

  const aiSkills = async () => {
    if (!Pro.guardAI()) return;
    setBusy((b) => ({ ...b, skills: true }));
    const out = await AI.suggestSkills(resume);
    setBusy((b) => ({ ...b, skills: false }));
    if (out) {
      const have = new Set(resume.skills.map((s) => String(window.skillName(s)).toLowerCase()));
      const adds = out.filter((n) => !have.has(String(n).toLowerCase())).map((n) => ({ name: n, level: 3 }));
      set({ skills: [...resume.skills, ...adds] }); Pro.recordAI(); flash(`Added ${adds.length} suggested skills`);
    }
    else flash("Couldn't reach AI — try again");
  };

  // ---- experience CRUD ----
  const addJob = () => set({ experience: [...resume.experience, { id: uid(), role: "New role", company: "Company", start: "2024", end: "Present", location: "", bullets: ["Describe what you did and the impact."] }] });
  const delJob = (id) => set({ experience: resume.experience.filter((e) => e.id !== id) });
  const addBullet = (eid) => setExp(eid, { bullets: [...resume.experience.find((e) => e.id === eid).bullets, ""] });
  const delBullet = (eid, idx) => setExp(eid, { bullets: resume.experience.find((e) => e.id === eid).bullets.filter((_, i) => i !== idx) });

  const addEdu = () => set({ education: [...resume.education, { id: uid(), school: "School", degree: "Degree", start: "2020", end: "2024" }] });
  const delEdu = (id) => set({ education: resume.education.filter((e) => e.id !== id) });

  // ---- skills (now carry a proficiency level on a 1..5 scale) ----
  const [skillDraft, setSkillDraft] = useState("");
  const addSkill = () => { const v = skillDraft.trim(); if (v) { set({ skills: [...resume.skills, { name: v, level: 4 }] }); setSkillDraft(""); } };
  const delSkill = (i) => set({ skills: resume.skills.filter((_, x) => x !== i) });
  const setSkillName = (i, name) => set({ skills: resume.skills.map((s, x) => x === i ? { name, level: window.normSkill(s, i).level } : s) });
  const setSkillLevel = (i, level) => set({ skills: resume.skills.map((s, x) => x === i ? { name: window.skillName(s), level } : s) });

  const accentOptions = [
    { a: "#6d5cff", b: "#ff5ca8" }, { a: "#13b6a8", b: "#5b8cff" },
    { a: "#f4663a", b: "#ffb43d" }, { a: "#7c3aed", b: "#06b6d4" },
    { a: "#111111", b: "#6b6b6b" }, { a: "#e0467c", b: "#ff9e6d" },
  ];

  return (
    <div className={`builder layout-${layout}`}>
      {/* ===== toolbar ===== */}
      <div className="b-toolbar">
        <button className="btn btn-quiet btn-sm" onClick={onGallery}><Icons.arrowL size={15} /> Templates</button>
        <div className="b-tool-mid">
          <div className="tpl-switch">
            <Icons.layers size={15} style={{ color: "var(--ink-3)" }} />
            <select value={templateId} onChange={(e) => setTemplateId(e.target.value)}>
              {tpls.map((t) => <option key={t.id} value={t.id}>{t.name}</option>)}
            </select>
          </div>
          <div className="accent-row">
            {accentOptions.map((o, i) => (
              <button key={i} className={`acc-sw ${pa.a === o.a ? "on" : ""}`}
                style={{ background: `linear-gradient(135deg, ${o.a}, ${o.b})` }}
                onClick={() => setAccent({ ...o, custom: true })} title="Accent" />
            ))}
            <button className={`acc-sw reset ${!accent.custom ? "on" : ""}`} title="Match template"
              onClick={() => setAccent({ custom: false })}><Icons.refresh size={12} /></button>
          </div>
        </div>
        <div className="b-tool-end">
          <button className="btn btn-quiet btn-sm" onClick={onCoverStudio} title="Edit the matching cover letter">
            <Icons.mail size={15} /> Cover letter
          </button>
          <ResumeScore resume={resume} />
          {!isPro && (
            <span className={`ai-quota ${aiRemaining <= 0 ? "out" : ""}`} title="Free AI rewrites">
              <Icons.magic size={13} /> {aiRemaining > 0 ? <><b>{aiRemaining}</b> AI left</> : "AI used up"}
            </span>
          )}
          <ExportControls getNode={() => innerRef.current}
            getText={() => resumeToText(resume)}
            fileName={`${(resume.name || "Resume").trim()} — Résumé`} reason="pdf" />
        </div>
      </div>

      {/* ===== panels ===== */}
      <div className="b-panels">
        {/* ---- FORM ---- */}
        <div className="b-form">
          <div className="form-scroll">
            <div className="form-intro">
              <h2>Edit your résumé</h2>
              <p>Edit here, or <b>click any text on the résumé</b> to change it in place — clicking also jumps you to the matching section below. Use the <Icons.magic size={13} style={{ verticalAlign: "-2px", color: "var(--acc)" }} /> button to sharpen any line with AI.</p>
            </div>

            <Section icon={Icons.grid} title="Résumé sections">
              <SectionOrganizer resume={resume} setResume={setResume} />
            </Section>

            <Section icon={Icons.user} title="Basics" secKey="basics">
              <PhotoField photo={resume.photo} onChange={(v) => set({ photo: v })} name={resume.name} />
              <Field label="Full name" value={resume.name} onChange={(v) => set({ name: v })} placeholder="Your name" />
              <Field label="Headline / target role" value={resume.title} onChange={(v) => set({ title: v })} placeholder="e.g. Product Designer" />
              <div className="grid-2">
                <Field label="Email" value={resume.email} onChange={(v) => set({ email: v })} />
                <Field label="Phone" value={resume.phone} onChange={(v) => set({ phone: v })} />
              </div>
              <div className="grid-2">
                <Field label="Website" value={resume.website} onChange={(v) => set({ website: v })} />
                <Field label="Location" value={resume.location} onChange={(v) => set({ location: v })} />
              </div>
            </Section>

            <Section icon={Icons.pen} title="Summary" secKey="summary">
              <div className="sec-ai-head">
                <span className="field-l">Professional summary</span>
                <button className={`ai-chip ${busy.summary ? "busy" : ""}`} onClick={aiSummary} disabled={busy.summary}>
                  {busy.summary ? <Icons.refresh size={13} className="spin" /> : <Icons.magic size={13} />}
                  {busy.summary ? "Writing…" : "Write with AI"}
                </button>
              </div>
              <AutoText value={resume.summary} onChange={(v) => set({ summary: v })} placeholder="A few lines about who you are and what you're looking for." />
            </Section>

            <Section icon={Icons.brief} title="Experience" count={resume.experience.length} secKey="experience">
              {resume.experience.map((j) => (
                <div className="card-edit" key={j.id}>
                  <div className="card-edit-top">
                    <span className="drag-h"><Icons.drag size={16} /></span>
                    <button className="del-btn" onClick={() => delJob(j.id)} title="Remove"><Icons.trash size={14} /></button>
                  </div>
                  <Field label="Role" value={j.role} onChange={(v) => setExp(j.id, { role: v })} />
                  <div className="grid-2">
                    <Field label="Company" value={j.company} onChange={(v) => setExp(j.id, { company: v })} />
                    <Field label="Location" value={j.location} onChange={(v) => setExp(j.id, { location: v })} />
                  </div>
                  <div className="grid-2">
                    <Field label="Start" value={j.start} onChange={(v) => setExp(j.id, { start: v })} mono />
                    <Field label="End" value={j.end} onChange={(v) => setExp(j.id, { end: v })} mono />
                  </div>
                  <span className="field-l" style={{ marginTop: 6 }}>Highlights</span>
                  <div className="bullets">
                    {j.bullets.map((b, i) => (
                      <div className="bullet-row" key={i}>
                        <span className="bullet-dot" />
                        <AutoText value={b} onChange={(v) => setBullet(j.id, i, v)} placeholder="Achievement or responsibility…" />
                        <div className="bullet-tools">
                          <AIBulletBtn busy={busy[`b-${j.id}-${i}`]} onMode={(m) => aiBullet(j.id, i, m)} />
                          <button className="bul-del" onClick={() => delBullet(j.id, i)}><Icons.close size={13} /></button>
                        </div>
                      </div>
                    ))}
                    <button className="add-inline" onClick={() => addBullet(j.id)}><Icons.plus size={13} /> Add highlight</button>
                  </div>
                </div>
              ))}
              <button className="add-card" onClick={addJob}><Icons.plus size={15} /> Add experience</button>
            </Section>

            <Section icon={Icons.star} title="Skills" count={resume.skills.length} secKey="skills">
              <div className="sec-ai-head">
                <span className="field-l">Your skills</span>
                <button className={`ai-chip ${busy.skills ? "busy" : ""}`} onClick={aiSkills} disabled={busy.skills}>
                  {busy.skills ? <Icons.refresh size={13} className="spin" /> : <Icons.spark size={13} />}
                  {busy.skills ? "Thinking…" : "Suggest skills"}
                </button>
              </div>
              <div className="skill-levels">
                {resume.skills.map((s, i) => {
                  const ns = window.normSkill(s, i);
                  return (
                    <div className="skill-lvl-row" key={i}>
                      <input className="fld skill-lvl-name" value={ns.name} placeholder="Skill"
                        onChange={(e) => setSkillName(i, e.target.value)} />
                      <LevelPicker value={ns.level} onChange={(lv) => setSkillLevel(i, lv)} />
                      <span className="skill-lvl-word">{window.LEVEL_WORDS[ns.level]}</span>
                      <button className="skill-lvl-del" onClick={() => delSkill(i)} title="Remove"><Icons.close size={13} /></button>
                    </div>
                  );
                })}
              </div>
              <div className="skill-add">
                <input className="fld" value={skillDraft} placeholder="Add a skill and press Enter"
                  onChange={(e) => setSkillDraft(e.target.value)}
                  onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addSkill(); } }} />
                <button className="btn btn-ghost btn-sm" onClick={addSkill}><Icons.plus size={14} /></button>
              </div>
              <p className="skill-scale-hint">Set how much you've used each one — the level shows as a scale on graphic templates (dots, segments, signal).</p>
            </Section>

            <Section icon={Icons.cap} title="Education" count={resume.education.length} secKey="education">
              {resume.education.map((e) => (
                <div className="card-edit" key={e.id}>
                  <div className="card-edit-top">
                    <span className="drag-h"><Icons.drag size={16} /></span>
                    <button className="del-btn" onClick={() => delEdu(e.id)}><Icons.trash size={14} /></button>
                  </div>
                  <Field label="School" value={e.school} onChange={(v) => set({ education: resume.education.map((x) => x.id === e.id ? { ...x, school: v } : x) })} />
                  <Field label="Degree" value={e.degree} onChange={(v) => set({ education: resume.education.map((x) => x.id === e.id ? { ...x, degree: v } : x) })} />
                  <div className="grid-2">
                    <Field label="Start" value={e.start} onChange={(v) => set({ education: resume.education.map((x) => x.id === e.id ? { ...x, start: v } : x) })} mono />
                    <Field label="End" value={e.end} onChange={(v) => set({ education: resume.education.map((x) => x.id === e.id ? { ...x, end: v } : x) })} mono />
                  </div>
                </div>
              ))}
              <button className="add-card" onClick={addEdu}><Icons.plus size={15} /> Add education</button>
            </Section>

            {effectiveOrder(resume).filter((k) => EXTRA_KEYS.includes(k)).map((k) => {
              const def = SECTION_DEFS[k];
              const Ic = Icons[def.icon] || Icons.tag;
              const count = Array.isArray(resume[k]) ? resume[k].length : undefined;
              return (
                <Section key={k} icon={Ic} title={def.label} count={count} secKey={k}>
                  <ExtraSectionEditor k={k} resume={resume} setResume={setResume} />
                </Section>
              );
            })}

            <div className="form-foot">
              <Icons.check size={14} style={{ color: "var(--acc)" }} /> Your résumé, ready to download. Need a cover letter? Open the <b>Cover letters</b> tab.
            </div>
          </div>
        </div>

        {/* ---- PREVIEW ---- */}
        <div className="b-preview" ref={stageRef}>
          <div className="preview-bar">
            <span className="pv-name">{tpl.name}</span>
            <span className="pv-hint"><Icons.pen size={11} /> Click any text to edit</span>
            <span className="pv-zoom">{Math.round(zoom * 100)}%</span>
          </div>
          <div className="preview-scroll" onMouseDown={onPreviewMouseDown}>
            <div className="preview-paper"
              style={{ width: 768 * zoom, height: paperH * zoom }}>
              <div ref={innerRef} style={{ transform: `scale(${zoom})`, transformOrigin: "top left", width: 768 }}>
                <PagedPaper data={resume} templateId={templateId} skillStyle={skillStyle}
                  accent={pa.custom ? pa.a : undefined} accent2={pa.custom ? pa.b : undefined} />
              </div>
            </div>
          </div>
        </div>
      </div>

      <Toast msg={toast} />
    </div>
  );
}

window.Builder = Builder;
