/* global React, ReactDOM, CVDocument, emptyData, validateStep, blank, applyLimits,
   StepIdentity, StepSkills, StepStrengths, StepLanguages, StepCourses,
   StepEducation, StepExperience, StepProjects, Head, MAX */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

const STORAGE_KEY = "sn_cv_record_v1";
const STEP_KEY = "sn_cv_step_v1";

// ---- Backend mode -------------------------------------------------------
// false  → prototipo: guarda en localStorage, PDF por impresión del navegador.
// true   → Cloudflare: Save crea/actualiza vía /api/candidates (acceso ABIERTO),
//          carga /api/settings (límites), y devuelve un enlace de edición.
const USE_BACKEND = true;
const API_BASE = ""; // mismo origen al desplegar

// Enlace de retorno/edición: ?cv=<id>&t=<token>. Si no viene, es un CV nuevo.
const AUTH = (() => {
  const p = new URLSearchParams(location.search);
  return { id: p.get("cv"), token: p.get("t") };
})();

// Dónde guardar el borrador mientras se escribe:
// - Backend (producción): sessionStorage — sobrevive a un refresh accidental, pero
//   una pestaña/visita nueva SIEMPRE arranca en blanco (salvo enlace de edición).
// - Prototipo local: localStorage (persistente), como antes.
const DRAFT_STORE = USE_BACKEND ? window.sessionStorage : window.localStorage;

const STEPS = [
  { id: "identity", label: "Candidate", comp: StepIdentity },
  { id: "skills", label: "Skills", comp: StepSkills },
  { id: "strengths", label: "Strengths", comp: StepStrengths },
  { id: "languages", label: "Languages", comp: StepLanguages },
  { id: "courses", label: "Courses", comp: StepCourses },
  { id: "education", label: "Education", comp: StepEducation },
  { id: "experience", label: "Experience", comp: StepExperience },
  { id: "projects", label: "Projects", comp: StepProjects },
  { id: "review", label: "Review & Export", comp: null },
];

function loadData() {
  try {
    const raw = DRAFT_STORE.getItem(STORAGE_KEY);
    if (raw) {
      const parsed = JSON.parse(raw);
      const merged = { ...emptyData(), ...parsed, candidate: { ...emptyData().candidate, ...(parsed.candidate || {}) } };
      // Migrate v1 experience shape: responsibilities/achievements string → bullets array
      merged.experience = (merged.experience || []).map(x => ({
        ...x,
        responsibilities: Array.isArray(x.responsibilities) ? x.responsibilities : (x.responsibilities ? [x.responsibilities] : [""]),
        achievements: Array.isArray(x.achievements) ? x.achievements : (x.achievements ? [x.achievements] : [""]),
      }));
      return merged;
    }
  } catch (e) { /* ignore */ }
  return emptyData();
}

// ---------- Review & Export ----------
function ReturnLink({ url }) {
  const [copied, setCopied] = useState(false);
  return (
    <div style={{ marginTop: 16, padding: "14px 16px", background: "rgba(174,204,87,.18)", border: "1px solid var(--sn-green)", borderRadius: 10 }}>
      <div style={{ fontWeight: 800, color: "var(--sn-blue)", fontSize: 14, marginBottom: 4 }}>✓ Your CV has been saved!</div>
      <div style={{ fontSize: 12.5, color: "var(--sn-ink-70)", lineHeight: 1.5, marginBottom: 10 }}>
        Keep this link to come back and edit your CV anytime. <b>It is your personal access — do not share it.</b>
      </div>
      <div style={{ display: "flex", gap: 8 }}>
        <input readOnly value={url} onClick={(e) => e.target.select()}
          style={{ flex: 1, fontFamily: "ui-monospace, monospace", fontSize: 11.5, border: "1px solid var(--sn-gray-cool)", borderRadius: 6, padding: "9px 11px", background: "#fff", color: "var(--sn-ink)" }} />
        <button type="button" className="btn btn-blue" style={{ padding: "9px 16px", fontSize: 13 }}
          onClick={() => { navigator.clipboard.writeText(url); setCopied(true); setTimeout(() => setCopied(false), 1500); }}>
          {copied ? "Copied!" : "Copy"}
        </button>
      </div>
    </div>
  );
}

// Popup shown right after a successful save — makes the edit link impossible to miss.
function SaveModal({ url, onClose }) {
  const [copied, setCopied] = useState(false);
  return (
    <div className="save-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="save-modal" role="dialog" aria-modal="true">
        <div className="sm-check" aria-hidden="true">✓</div>
        <h3>Your CV has been saved!</h3>
        <p>
          <b>Save this link</b> — it is your personal access to come back and edit your CV anytime.
          Copy it and keep it somewhere safe (email it to yourself or save it in your notes). Do not share it.
        </p>
        <div className="sm-url">
          <input readOnly value={url} onClick={(e) => e.target.select()} />
          <button type="button" className="btn btn-blue" style={{ padding: "9px 16px", fontSize: 13 }}
            onClick={() => { navigator.clipboard.writeText(url); setCopied(true); setTimeout(() => setCopied(false), 1800); }}>
            {copied ? "Copied!" : "Copy link"}
          </button>
        </div>
        <div className="sm-acts">
          <button type="button" className="btn btn-ghost" onClick={onClose}>I saved my link — close</button>
        </div>
      </div>
    </div>
  );
}

function StepReview({ d, saved, onSave, onPrint }) {
  const counts = [
    ["Technical skills", d.technicalKnowledge.filter(s => s.skillName).length, MAX.technicalKnowledge],
    ["Strengths", d.strengths.filter(s => s.name).length, MAX.strengths],
    ["Languages", d.languages.filter(l => l.language).length, MAX.languages],
    ["Courses / certifications", d.courses.filter(c => c.name).length, MAX.courses],
    ["Education", d.education.filter(e => e.degree || e.university).length, MAX.education],
    ["Professional experience", d.experience.filter(e => e.company || e.jobTitle).length, MAX.experience],
    ["Key projects", d.projects.filter(p => p.title).length, MAX.projects],
  ];
  return (
    <div>
      <Head eyebrow="Step 9 · Review & Export" title="Review & generate CV"
        sub="Check the live preview on the right. Save to store the record, then download the branded PDF." />
      <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 22 }}>
        {counts.map(([k, n, m]) => (
          <div key={k} style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "8px 12px", background: "var(--sn-offwhite)", borderRadius: 6 }}>
            <span style={{ fontWeight: 600 }}>{k}</span>
            <span style={{ fontWeight: 800, color: "var(--sn-blue)" }}>{n} / {m}</span>
          </div>
        ))}
      </div>

      <button type="button" className="btn btn-primary" style={{ width: "100%", marginBottom: 12 }} onClick={onSave}>
        {saved ? "✓ Saved — save changes" : "Save my CV"}
      </button>
      <button type="button" className="btn btn-blue" style={{ width: "100%" }} onClick={onPrint}>
        Download CV as PDF
      </button>

      {saved && saved.editUrl ? <ReturnLink url={saved.editUrl} /> : saved ? (
        <div style={{ marginTop: 16, padding: "12px 14px", background: "rgba(174,204,87,.18)", border: "1px solid var(--sn-green)", borderRadius: 8, fontSize: 13 }}>
          <b>CV saved.</b> Stored locally as <code>{saved.id}</code>.
        </div>
      ) : null}

      <div className="field-hint" style={{ marginTop: 16 }}>
        Tip: in the print dialog, set margins to “None” — background colors are preserved automatically.
      </div>
    </div>
  );
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "formLayout": "guided",
  "density": "comfortable",
  "ctaColor": "green",
  "photoShape": "square"
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [data, setData] = useState(loadData);
  const [step, setStep] = useState(() => {
    const s = Number(DRAFT_STORE.getItem(STEP_KEY));
    return Number.isFinite(s) && s >= 0 && s < STEPS.length ? s : 0;
  });
  const [touched, setTouched] = useState({});  // {stepId: true}
  const [saved, setSaved] = useState(null);     // {id, at, token, editUrl}
  const [showLinkModal, setShowLinkModal] = useState(false);
  const [booted, setBooted] = useState(!USE_BACKEND);
  const [, bumpLimits] = useState(0);
  const previewRef = useRef(null);
  const scalerRef = useRef(null);

  // Backend: carga límites configurables y, si hay enlace de edición, el registro.
  useEffect(() => {
    if (!USE_BACKEND) return;
    (async () => {
      try {
        const res = await fetch(`${API_BASE}/api/settings`);
        if (res.ok) { applyLimits(await res.json()); bumpLimits(v => v + 1); }
      } catch (e) { /* defaults */ }

      if (AUTH.id && AUTH.token) {
        try {
          const res = await fetch(`${API_BASE}/api/candidates/${AUTH.id}?t=${encodeURIComponent(AUTH.token)}`,
            { headers: { "Authorization": "Bearer " + AUTH.token } });
          if (res.ok) {
            const rec = await res.json();
            const base = emptyData();
            setData({
              ...base,
              candidate: { ...base.candidate, ...rec.candidate, photo: rec.candidate.photoUrl || null },
              technicalKnowledge: rec.technicalKnowledge?.length ? rec.technicalKnowledge : base.technicalKnowledge,
              strengths: rec.strengths?.length ? rec.strengths : base.strengths,
              languages: rec.languages?.length ? rec.languages : base.languages,
              courses: rec.courses?.length ? rec.courses : base.courses,
              education: rec.education?.length ? rec.education : base.education,
              experience: rec.experience?.length ? rec.experience.map(x => ({
                ...x,
                responsibilities: Array.isArray(x.responsibilities) ? x.responsibilities : (x.responsibilities ? [x.responsibilities] : [""]),
                achievements: Array.isArray(x.achievements) ? x.achievements : (x.achievements ? [x.achievements] : [""]),
              })) : base.experience,
              projects: rec.projects?.length ? rec.projects : base.projects,
            });
            const editUrl = `${location.origin}/CV%20Builder.html?cv=${AUTH.id}&t=${encodeURIComponent(AUTH.token)}`;
            setSaved({ id: AUTH.id, at: 0, token: AUTH.token, editUrl });
          }
        } catch (e) { /* sigue con datos locales/vacíos */ }
      }
      setBooted(true);
    })();
  }, []);

  // persist draft
  useEffect(() => { try { DRAFT_STORE.setItem(STORAGE_KEY, JSON.stringify(data)); } catch (e) {} }, [data]);
  useEffect(() => { try { DRAFT_STORE.setItem(STEP_KEY, String(step)); } catch (e) {} }, [step]);

  // handlers
  const h = useMemo(() => ({
    setCandidate: (field, val) => setData(d => ({ ...d, candidate: { ...d.candidate, [field]: val } })),
    setItem: (section, i, field, val) => setData(d => {
      const arr = d[section].slice(); arr[i] = { ...arr[i], [field]: val }; return { ...d, [section]: arr };
    }),
    addItem: (section) => setData(d => {
      const factory = { technicalKnowledge: blank.skill, strengths: blank.strength, languages: blank.language,
        courses: blank.course, education: blank.education, experience: blank.experience, projects: blank.project }[section];
      if (d[section].length >= MAX[section]) return d;
      return { ...d, [section]: [...d[section], factory()] };
    }),
    removeItem: (section, i) => setData(d => ({ ...d, [section]: d[section].filter((_, j) => j !== i) })),
  }), []);

  const cur = STEPS[step];
  const errors = useMemo(() => validateStep(cur.id, data), [cur.id, data]);
  const showErrors = touched[cur.id] ? errors : {};

  // per-step status for chips
  const stepStatus = (s, i) => {
    if (i === step) return "active";
    if (touched[s.id] && Object.keys(validateStep(s.id, data)).length) return "error";
    if (i < step) return "done";
    return "";
  };

  function goNext() {
    const e = validateStep(cur.id, data);
    setTouched(t => ({ ...t, [cur.id]: true }));
    if (Object.keys(e).length) {
      document.querySelector(".form-body").scrollTo({ top: 0, behavior: "smooth" });
      return;
    }
    setStep(s => Math.min(STEPS.length - 1, s + 1));
    document.querySelector(".form-body").scrollTo({ top: 0 });
  }
  function goPrev() { setStep(s => Math.max(0, s - 1)); document.querySelector(".form-body").scrollTo({ top: 0 }); }
  function goTo(i) { setTouched(t => ({ ...t, [cur.id]: true })); setStep(i); }

  async function save() {
    if (USE_BACKEND) {
      try {
        const editToken = saved?.token || AUTH.token || null;
        const res = await fetch(`${API_BASE}/api/candidates`, {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ ...data, token: editToken }),
        });
        const out = await res.json();
        if (!res.ok) { alert("Could not save your CV:\n" + (out.details || [out.error]).join("\n")); return; }
        setSaved({ id: out.id, at: Date.now(), token: out.token, editUrl: out.editUrl });
        setShowLinkModal(true);
        // refleja el enlace en la URL para que un refresh siga en modo edición
        try { history.replaceState(null, "", `?cv=${out.id}&t=${encodeURIComponent(out.token)}`); } catch (e) {}
      } catch (e) { alert("Network error while saving. Please try again."); }
      return;
    }
    const id = saved?.id || "CV-" + Math.random().toString(36).slice(2, 8).toUpperCase();
    const demoUrl = `${location.origin}${location.pathname}?cv=${id}&t=demo`;
    setSaved({ id, at: Date.now(), token: "demo", editUrl: demoUrl });
    setShowLinkModal(true);
    try { DRAFT_STORE.setItem(STORAGE_KEY, JSON.stringify(data)); } catch (e) {}
  }
  function printCV() {
    if (USE_BACKEND && saved?.id) {
      const tok = saved.token ? `&t=${encodeURIComponent(saved.token)}` : "";
      window.open(`${API_BASE}/api/candidates/${saved.id}/pdf?photoShape=${t.photoShape}${tok}`, "_blank");
      return;
    }
    // PDF filename = browser print dialog uses document.title
    const prev = document.title;
    const nm = (data.candidate.fullName || "").trim();
    document.title = nm ? `Scale Nearshoring — ${nm}` : "Scale Nearshoring — CV";
    window.print();
    setTimeout(() => { document.title = prev; }, 1000);
  }

  // fit-to-width preview scaling (uses CSS zoom)
  useEffect(() => {
    function fit() {
      const pane = previewRef.current, sc = scalerRef.current;
      if (!pane || !sc) return;
      const avail = pane.clientWidth - 56;
      const z = Math.max(0.32, Math.min(1, avail / 816));
      sc.style.zoom = z;
    }
    fit();
    const ro = new ResizeObserver(fit);
    if (previewRef.current) ro.observe(previewRef.current);
    return () => ro.disconnect();
  }, []);

  // apply photo-shape tweak to CV doc
  useEffect(() => {
    const r = { square: "6px", rounded: "22px", circle: "50%" }[t.photoShape] || "6px";
    document.documentElement.style.setProperty("--cv-photo-radius", r);
  }, [t.photoShape]);

  const StepComp = cur.comp;
  const progress = ((step) / (STEPS.length - 1)) * 100;
  const appClass = [
    "app",
    (t.formLayout === "focus" && cur.id !== "review") ? "layout-focus" : "",
    t.density === "compact" ? "density-compact" : "",
    t.ctaColor === "blue" ? "cta-blue" : "",
  ].join(" ");

  if (USE_BACKEND && !booted) {
    return (
      <div style={{ height: "100vh", display: "grid", placeItems: "center", background: "var(--sn-offwhite)" }}>
        <div style={{ textAlign: "center" }}>
          <img src="assets/logo-color.png" alt="Scale Nearshoring" style={{ height: 36, marginBottom: 18, opacity: .9 }} />
          <div style={{ width: 24, height: 24, margin: "0 auto", border: "3px solid var(--sn-gray-cool)", borderTopColor: "var(--sn-blue)", borderRadius: "50%", animation: "sp .7s linear infinite" }} />
          <style>{"@keyframes sp{to{transform:rotate(360deg)}}"}</style>
        </div>
      </div>
    );
  }

  return (
    <div className={appClass}>
      <div className="pane-form">
        <div className="form-top">
          <div className="brandbar">
            <img src="assets/logo-color.png" alt="Scale Nearshoring" />
            <span className="tagline">Candidate CV Builder</span>
          </div>
          <div className="steps">
            {STEPS.map((s, i) => (
              <button key={s.id} className={"step-chip " + stepStatus(s, i)} onClick={() => goTo(i)}>
                <span className="num">{stepStatus(s, i) === "done" ? "✓" : i + 1}</span>{s.label}
              </button>
            ))}
          </div>
          <div className="progress-track"><div className="progress-fill" style={{ width: progress + "%" }} /></div>
          <div style={{ height: 14 }} />
        </div>

        <div className="form-body">
          {cur.id === "review"
            ? <StepReview d={data} saved={saved} onSave={save} onPrint={printCV} />
            : <StepComp d={data} errors={showErrors} h={h} />}
        </div>

        <div className="form-nav">
          <button className="btn btn-ghost" onClick={goPrev} disabled={step === 0}>← Back</button>
          <div className="flex-grow" />
          {step < STEPS.length - 1
            ? <button className="btn btn-primary" onClick={goNext}>Continue →</button>
            : <button className="btn btn-blue" onClick={printCV}>Download PDF</button>}
        </div>
      </div>

      <div className="pane-preview" ref={previewRef}>
        <div className="cv-toolbar">
          <div>
            <div className="ttl">Live CV preview</div>
            <div className="meta">Scale Nearshoring · Letter · flows across pages as you type</div>
          </div>
          <div className="acts">
            <button className="btn btn-ghost" style={{ padding: "9px 16px", fontSize: 13 }} onClick={save}>Save</button>
            <button className="btn btn-blue" style={{ padding: "9px 16px", fontSize: 13 }} onClick={printCV}>Download PDF</button>
          </div>
        </div>
        <div className="cv-scaler" ref={scalerRef}>
          <CVDocument data={data} />
        </div>
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection label="Form experience" />
        <TweakRadio label="Layout" value={t.formLayout}
          options={["guided", "focus"]} onChange={(v) => setTweak("formLayout", v)} />
        <TweakRadio label="Density" value={t.density}
          options={["comfortable", "compact"]} onChange={(v) => setTweak("density", v)} />
        <TweakRadio label="Primary button" value={t.ctaColor}
          options={["green", "blue"]} onChange={(v) => setTweak("ctaColor", v)} />
        <TweakSection label="CV document" />
        <TweakRadio label="Photo shape" value={t.photoShape}
          options={["square", "rounded", "circle"]} onChange={(v) => setTweak("photoShape", v)} />
      </TweaksPanel>

      {showLinkModal && saved?.editUrl ? (
        <SaveModal url={saved.editUrl} onClose={() => setShowLinkModal(false)} />
      ) : null}
    </div>
  );
}

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