// registration-app.jsx — orchestrator: state, navigation, transitions,
// validation, submit.

// ── CSS scoped to the registration root ────────────────────────────────
if (typeof document !== "undefined" && !document.getElementById("reg-app-css")) {
  const s = document.createElement("style");
  s.id = "reg-app-css";
  s.textContent = `
    :root { color-scheme: dark; }
    body { background:#0c0c0c; color:#f3efe9; }
    .reg-root {
      --bg:#0c0c0c;
      --fg:#f3efe9;
      --rule: rgba(243,239,233,0.14);
      --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
      --font-body: "DM Sans", ui-sans-serif, system-ui, sans-serif;
      --font-display: "DM Sans", ui-sans-serif, system-ui, sans-serif;
      min-height: 100vh;
      display: flex; flex-direction: column;
      font-family: var(--font-body);
    }

    /* Top bar */
    .reg-top {
      display: flex; align-items: center; justify-content: space-between;
      padding: 22px clamp(24px, 4vw, 56px);
      border-bottom: 1px solid var(--rule);
      font-family: var(--mono); font-size: 10.5px;
      letter-spacing: .18em; text-transform: uppercase;
      color: rgba(243,239,233,0.65);
    }
    .reg-mark { color: #f3efe9; font-weight: 500; }
    .reg-progress-wrap {
      display: flex; align-items: center; gap: 16px;
      flex: 1; justify-content: center;
    }
    .reg-progress-bar {
      flex: 0 1 320px; height: 1px;
      background: rgba(243,239,233,0.14);
      position: relative; overflow: hidden;
    }
    .reg-progress-fill {
      position: absolute; left: 0; top: 0; bottom: 0;
      background: #f3efe9;
      transition: width .45s cubic-bezier(.4,0,.2,1);
    }
    .reg-progress-text {
      font-variant-numeric: tabular-nums;
      color: rgba(243,239,233,0.78);
    }
    .reg-exit {
      appearance: none; border: 0; background: transparent;
      color: rgba(243,239,233,0.55); cursor: pointer;
      font: inherit; letter-spacing: inherit; text-transform: inherit;
      padding: 4px 8px;
    }
    .reg-exit:hover { color: #f3efe9; }

    /* Stage */
    .reg-stage {
      flex: 1; position: relative;
      display: flex; align-items: center; justify-content: center;
      padding: clamp(48px, 6vw, 96px) clamp(24px, 4vw, 56px);
      overflow: hidden;
    }
    .reg-step {
      width: 100%; max-width: 880px;
      display: flex; flex-direction: column; align-items: stretch;
      opacity: 1;
      transition: opacity .35s, transform .45s cubic-bezier(.4,0,.2,1);
    }
    .reg-step.enter-forward { opacity: 0; transform: translateX(60px); }
    .reg-step.enter-back    { opacity: 0; transform: translateX(-60px); }
    .reg-step.idle          { opacity: 1; transform: none; }
    .reg-step.exit-forward  { opacity: 0; transform: translateX(-60px); }
    .reg-step.exit-back     { opacity: 0; transform: translateX(60px); }

    /* For Welcome / Done steps — center align */
    .reg-stage.centered .reg-step {
      align-items: center;
    }

    /* Bottom nav */
    .reg-nav {
      display: flex; align-items: center; justify-content: space-between;
      padding: 20px clamp(24px, 4vw, 56px);
      border-top: 1px solid var(--rule);
      gap: 12px;
    }

    /* Buttons */
    .reg-btn {
      appearance: none; cursor: pointer;
      font-family: var(--font-body); font-weight: 500;
      font-size: 14px; letter-spacing: .02em;
      padding: 13px 22px; border-radius: 999px;
      display: inline-flex; align-items: center; gap: 10px;
      transition: background .15s, color .15s, transform .12s, opacity .15s;
      border: 1px solid transparent;
    }
    .reg-btn:active { transform: translateY(1px); }
    .reg-btn:disabled { opacity: 0.4; cursor: not-allowed; }
    .reg-btn .arrow { transition: transform .18s; }
    .reg-btn.primary {
      background: #f3efe9; color: #0c0c0c;
    }
    .reg-btn.primary:hover:not(:disabled) {
      background: #fff;
    }
    .reg-btn.primary:hover:not(:disabled) .arrow {
      transform: translateX(4px);
    }
    .reg-btn.ghost {
      background: transparent; color: rgba(243,239,233,0.78);
      border-color: rgba(243,239,233,0.18);
    }
    .reg-btn.ghost:hover:not(:disabled) {
      color: #f3efe9; border-color: rgba(243,239,233,0.45);
    }

    /* Toast (form error summary) */
    .reg-toast {
      position: fixed; left: 50%; bottom: 92px; transform: translateX(-50%);
      background: #2a221a; color: #ffe8b3;
      border: 1px solid rgba(231,117,76,0.5);
      padding: 12px 18px; border-radius: 999px;
      font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
      text-transform: uppercase;
      box-shadow: 0 8px 32px rgba(0,0,0,0.45);
      pointer-events: none;
      z-index: 100;
      opacity: 0; transition: opacity .25s, transform .25s;
    }
    .reg-toast[data-show="1"] {
      opacity: 1; transform: translateX(-50%) translateY(0);
    }
  `;
  document.head.appendChild(s);
}

// ── State persistence ──────────────────────────────────────────────────
const LS_KEY = "model-registration.v1";

const DEFAULT_DATA = {
  firstName: "",
  lastName: "",
  alias: "",
  dob: "",
  email: "",
  phone: "",
  heightCm: "",
  cupSize: "",
  bandSize: "",
  breasts: "",
  dressSize: "",
  shoeSize: "",
  hairColor: "",
  hairLength: "",
  eyeColor: "",
  tattoos: { has: false, detail: "" },
  piercings: { has: false, detail: "" },
  nationality: "",
  basedInCity: "",
  basedInCountry: "",
  languages: [],
  availability: "",
  travel: "",
  bio: "",
  personality: "",
  media: [],
};

function loadSaved() {
  try {
    const raw = localStorage.getItem(LS_KEY);
    if (!raw) return DEFAULT_DATA;
    const parsed = JSON.parse(raw);
    // Media isn't persistable (object URLs die on reload) — drop it.
    return { ...DEFAULT_DATA, ...parsed, media: [] };
  } catch { return DEFAULT_DATA; }
}
function saveDraft(data) {
  try {
    const { media, ...rest } = data;
    localStorage.setItem(LS_KEY, JSON.stringify(rest));
  } catch {}
}

// ── Validation ─────────────────────────────────────────────────────────
function validateStep(stepIdx, data) {
  const R = window.REG_REQUIRED;
  const errors = {};
  const required = (keys) => keys.forEach((k) => {
    const v = data[k];
    const empty = v === "" || v === undefined || v === null
              || (Array.isArray(v) && v.length === 0);
    if (empty) errors[k] = "Please fill this in";
  });
  switch (stepIdx) {
    case 1: {
      required(R.basics);
      // Email shape sanity — full validation is server-side.
      if (data.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email))
        errors.email = "Please double-check that email address.";
      // Phone needs to start with + and have at least 8 digits total.
      if (data.phone && !/^\+\d[\d\s\-()]{7,}$/.test(data.phone))
        errors.phone = "Include the country code, e.g. +44 7700 900000.";
      break;
    }
    case 2: required(R.measurements); break;
    case 3: required(R.appearance);   break;
    case 4: required(R.origins);      break;
    case 5: required(R.work);         break;
    case 6: {
      required(R.about);
      // Short-form length floors so the profile doesn't show one-word bios.
      if (data.bio && data.bio.trim().length < 60) errors.bio = "A little longer please — at least a couple of sentences.";
      if (data.personality && data.personality.trim().length < 40) errors.personality = "A touch more — at least one full thought.";
      break;
    }
    case 7: {
      const n = (data.media || []).length;
      if (n < window.REG_MIN_MEDIA) errors.media = `At least ${window.REG_MIN_MEDIA} files needed. You have ${n}.`;
      break;
    }
    default: break;
  }
  return errors;
}

// ── Submit → emit profile-data.js shape ────────────────────────────────
function emitProfileDataFile(data) {
  const F = window.REG_FORMATTERS;
  const age    = F.age(data.dob);
  const cmH    = data.heightCm ? `${data.heightCm} cm` : "";
  const ftIn   = data.heightCm
    ? (() => { const t = data.heightCm/2.54; const ft = Math.floor(t/12); const i = Math.round(t - ft*12); return `${ft} ft ${i} in`; })()
    : "";
  const marks  = (() => {
    if (data.tattoos?.has || data.piercings?.has) {
      const parts = [];
      if (data.tattoos?.has)   parts.push(data.tattoos.detail ? `Tattoos: ${data.tattoos.detail}` : "Has tattoos");
      if (data.piercings?.has) parts.push(data.piercings.detail || "Piercings");
      return { v: data.tattoos?.has ? "Tattoos" : "Piercings", sub: parts.join(" · ") };
    }
    return { v: "No tattoos", sub: "no piercings" };
  })();

  const stats = [
    { k: "Age",         v: age,                                 sub: data.dob ? `b. ${new Date(data.dob).getFullYear()}` : "" },
    { k: "Height",      v: cmH,                                 sub: ftIn },
    { k: "Cup size",    v: data.cupSize,                         sub: data.bandSize },
    { k: "Breasts",     v: data.breasts },
    { k: "Dress",       v: data.dressSize ? `EU ${data.dressSize}` : "" },
    { k: "Shoe",        v: data.shoeSize ? `EU ${data.shoeSize}` : "" },
    { k: "Hair",        v: data.hairColor,                       sub: data.hairLength },
    { k: "Eyes",        v: data.eyeColor },
    { k: "Nationality", v: data.nationality },
    { k: "Based in",    v: [data.basedInCity, data.basedInCountry].filter(Boolean).join(", ") },
    { k: "Languages",   v: (data.languages || []).slice(0,3).map((l) => ({English:"EN",French:"FR",Italian:"IT",Spanish:"ES",German:"DE",Portuguese:"PT",Russian:"RU",Japanese:"JP",Mandarin:"ZH",Korean:"KO",Arabic:"AR"})[l] || l.slice(0,2).toUpperCase()).join(" · "),
                                                                 sub: (data.languages || []).join(", ") },
    { k: "Marks",       v: marks.v, sub: marks.sub },
    { k: "Availability", v: data.availability },
    { k: "Travel",      v: data.travel },
  ];

  const media = (data.media || []).map((m, idx) => {
    const out = {
      i: idx + 1,
      src: `assets/${String(idx+1).padStart(2,"0")}.${m.kind === "video" ? "mp4" : "jpg"}`,
      w: m.w, h: m.h,
    };
    if (m.kind === "video") {
      out.kind = "video";
      out.poster = `assets/${String(idx+1).padStart(2,"0")}.jpg`;
    }
    return out;
  });

  const payload = {
    firstName: data.firstName,
    lastName: data.lastName,
    agency: "Maison Reverie",
    city: data.basedInCity,
    stats,
    bio: data.bio,
    personality: data.personality,
    availability: { notice: data.availability, travel: data.travel },
    media,
  };

  const body = JSON.stringify(payload, null, 2);
  return `// Generated by the registration form on ${new Date().toISOString().slice(0,10)}.\n// Drop the applicant's photos into ./assets/ matching the src paths below.\n\nwindow.MODEL = ${body};\n`;
}

function downloadFile(filename, contents, mime = "text/plain") {
  const blob = new Blob([contents], { type: mime });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url; a.download = filename; a.click();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

// ── Step registry ──────────────────────────────────────────────────────
// Each entry: { key, component, isForm } — isForm means we run validation
// on Next and show the progress bar.
const STEPS = [
  { key: "welcome",      isForm: false },
  { key: "basics",       isForm: true  },
  { key: "measurements", isForm: true  },
  { key: "appearance",   isForm: true  },
  { key: "origins",      isForm: true  },
  { key: "work",         isForm: true  },
  { key: "words",        isForm: true  },
  { key: "portfolio",    isForm: true  },
  { key: "review",       isForm: false },
  { key: "done",         isForm: false },
];

function App() {
  const [step, setStep] = React.useState(0);
  const [data, setData] = React.useState(() => loadSaved());
  const [errors, setErrors] = React.useState({});
  const [direction, setDirection] = React.useState(1);
  const [submitting, setSubmitting] = React.useState(false);
  const [toast, setToast] = React.useState("");
  // For mounting the slide-in animation each step.
  const [stepKey, setStepKey] = React.useState(0);

  React.useEffect(() => { saveDraft(data); }, [data]);

  const update = (k, v) => {
    setData((d) => ({ ...d, [k]: v }));
    // Clear the error for this field as the user edits.
    if (errors[k]) setErrors((e) => { const n = { ...e }; delete n[k]; return n; });
  };

  const goTo = (idx, dir = 1) => {
    if (idx < 0 || idx >= STEPS.length) return;
    setDirection(dir);
    setStep(idx);
    setStepKey((k) => k + 1);
    setErrors({});
  };

  const next = () => {
    const errs = validateStep(step, data);
    if (Object.keys(errs).length) {
      setErrors(errs);
      setToast("Please complete the highlighted fields");
      setTimeout(() => setToast(""), 2500);
      return;
    }
    goTo(step + 1, 1);
  };
  const back = () => goTo(step - 1, -1);

  const submit = async () => {
    setSubmitting(true);
    // In production this is where the agency's API call goes — uploading
    // the media blobs and the JSON payload. For the demo we just simulate
    // a beat, then advance to the success screen.
    await new Promise((r) => setTimeout(r, 700));
    setSubmitting(false);
    goTo(STEPS.findIndex((s) => s.key === "done"), 1);
  };

  const downloadDataFile = () => {
    const content = emitProfileDataFile(data);
    downloadFile("profile-data.js", content, "application/javascript");
  };

  const current = STEPS[step];
  const formIdx = STEPS.filter((s) => s.isForm).findIndex((s) => s.key === current.key);
  const formTotal = STEPS.filter((s) => s.isForm).length;
  const showProgress = current.isForm || current.key === "review";
  const progressIdx = current.isForm ? formIdx + 1 : formTotal;
  const progressPct = (progressIdx / formTotal) * 100;

  const isCentered = current.key === "welcome" || current.key === "done";

  return (
    <div className="reg-root">
      <header className="reg-top">
        <span className="reg-mark">Maison Reverie</span>
        {showProgress ? (
          <div className="reg-progress-wrap">
            <span className="reg-progress-text">
              Step {String(progressIdx).padStart(2,"0")} / {String(formTotal).padStart(2,"0")}
            </span>
            <div className="reg-progress-bar">
              <div className="reg-progress-fill" style={{ width: `${progressPct}%` }}/>
            </div>
          </div>
        ) : (
          <span style={{ flex: 1, textAlign: "center" }}>
            {current.key === "welcome" ? "Talent application" : "Submission complete"}
          </span>
        )}
        {current.key !== "done" && (
          <button className="reg-exit" onClick={() => {
            if (confirm("Discard this draft and start over?")) {
              try { localStorage.removeItem(LS_KEY); } catch {}
              setData(DEFAULT_DATA);
              goTo(0, -1);
            }
          }}>Reset</button>
        )}
      </header>

      <main className={"reg-stage" + (isCentered ? " centered" : "")}>
        <StepView
          key={stepKey}
          stepKey={current.key}
          direction={direction}
          data={data}
          update={update}
          errors={errors}
          onStart={() => goTo(1, 1)}
          onEditStep={(idx) => goTo(idx, -1)}
          onSubmit={submit}
          submitting={submitting}
          onDownloadData={downloadDataFile}
        />
      </main>

      {current.key !== "welcome" && current.key !== "done" && current.key !== "review" && (
        <nav className="reg-nav">
          <button className="reg-btn ghost" onClick={back}>← Back</button>
          <button className="reg-btn primary" onClick={next}>
            Continue <span className="arrow">→</span>
          </button>
        </nav>
      )}

      <div className="reg-toast" data-show={toast ? "1" : "0"}>{toast}</div>
    </div>
  );
}

// StepView — wraps content with the slide animation lifecycle.
function StepView({ stepKey, direction, data, update, errors, onStart, onEditStep, onSubmit, submitting, onDownloadData }) {
  const [phase, setPhase] = React.useState(direction > 0 ? "enter-forward" : "enter-back");
  React.useEffect(() => {
    const t = requestAnimationFrame(() => setPhase("idle"));
    return () => cancelAnimationFrame(t);
  }, []);

  let content;
  switch (stepKey) {
    case "welcome":      content = <StepWelcome onStart={onStart}/>; break;
    case "basics":       content = <StepBasics       data={data} update={update} errors={errors}/>; break;
    case "measurements": content = <StepMeasurements data={data} update={update} errors={errors}/>; break;
    case "appearance":   content = <StepAppearance   data={data} update={update} errors={errors}/>; break;
    case "origins":      content = <StepOrigins      data={data} update={update} errors={errors}/>; break;
    case "work":         content = <StepWork         data={data} update={update} errors={errors}/>; break;
    case "words":        content = <StepWords        data={data} update={update} errors={errors}/>; break;
    case "portfolio":    content = <StepPortfolio    data={data} update={update} errors={errors}/>; break;
    case "review":       content = <StepReview       data={data} onEditStep={onEditStep} onSubmit={onSubmit} submitting={submitting}/>; break;
    case "done":         content = <StepDone         data={data} onDownloadData={onDownloadData}/>; break;
    default:             content = null;
  }

  return <div className={"reg-step " + phase}>{content}</div>;
}

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