/* ==================================================================
   Online Tests — teacher screen
   - Type picker (Blitz / Classical)
   - Paste raw MCQ text → Gemini formats → editable form
   - Save as draft / Save & make live (publishes to the student portal)
   ================================================================== */

const OT_ACCENT = "var(--blue-solid)";

const TYPE_PRESETS = [
  {
    id: "blitz",
    label: "Blitz",
    tagline: "Per-question timer · no back-tracking",
    detail: "Best for rapid practice and reflex drills. Each question gets a hard time limit; once it expires, the answer is locked.",
    accent: "var(--red-solid)",
  },
  {
    id: "classical",
    label: "Classical",
    tagline: "Total timer · free navigation",
    detail: "Best for full-length tests. One overall timer; students can navigate freely, mark for review, and use the palette.",
    accent: OT_ACCENT,
  },
  {
    id: "descriptive",
    label: "Descriptive",
    tagline: "Students upload photo answers · teacher grades manually",
    detail: "Long-form questions. Students attach photo(s) of their handwritten work per question. No options, no auto-grading — every mark comes from your review.",
    accent: "var(--amber-solid)",
  },
];

const OnlineTestsScreen = ({ setScreen }) => {
  const [testType,  setTestType]  = React.useState("classical");
  const [rawText,   setRawText]   = React.useState("");
  const [parsed,    setParsed]    = React.useState(null);
  const [warnings,  setWarnings]  = React.useState([]);
  const [formatting, setFormatting] = React.useState(false);
  const [saving,    setSaving]    = React.useState(false);
  const [err,       setErr]       = React.useState("");
  const [successId, setSuccessId] = React.useState(null);

  const handleFormat = async () => {
    if (!rawText.trim()) { setErr("Paste some MCQs first."); return; }
    setErr(""); setFormatting(true); setWarnings([]);
    try {
      const r = await window.AppApi.post("/online-tests/format", {
        raw_text: rawText, type: testType,
      });
      setParsed(r.parsed);
      setWarnings(Array.isArray(r.parsed?.warnings) ? r.parsed.warnings : []);
    } catch (e) {
      setErr(e.message || "Gemini failed to parse the text");
    } finally {
      setFormatting(false);
    }
  };

  const handleSave = async (publish) => {
    if (!parsed) { setErr("Format the test before saving."); return; }
    setErr(""); setSaving(true);
    try {
      const r = await window.AppApi.post("/online-tests", {
        parsed, type: testType, publish: !!publish,
        // Multi-section: send the chip set. Backend UNIONs students from
        // every section in the array when auto-enrolling.
        class_section_ids: (parsed.class_section_ids && parsed.class_section_ids.length)
          ? parsed.class_section_ids : undefined,
        subject_id: parsed.subject_id || undefined,
      });
      setSuccessId(r.id);
    } catch (e) {
      const errs = e.message?.includes("validation failed") ? e.message : (e.message || "Save failed");
      setErr(errs);
    } finally {
      setSaving(false);
    }
  };

  if (successId) {
    return (
      <OTScreenShell>
        <OTSuccess id={successId} onBack={() => setScreen("library")} onNew={() => {
          setSuccessId(null); setParsed(null); setRawText(""); setWarnings(""); setErr("");
        }}/>
      </OTScreenShell>
    );
  }

  return (
    <OTScreenShell>
      <div className="ot-split">
        {/* Left column — type picker (sticky) */}
        <div className="ot-split-aside">
          <OTLabel>Test type</OTLabel>
          <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: 10 }}>
            {TYPE_PRESETS.map((t) => (
              <TypeCard key={t.id} preset={t} selected={testType === t.id}
                        onClick={() => setTestType(t.id)} disabled={!!parsed}/>
            ))}
          </div>
          {parsed && (
            <div className="hint" style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 10, lineHeight: 1.45 }}>
              Type is locked once formatted. Click "Reset" on the test details card to start over.
            </div>
          )}
        </div>

        {/* Right column — paste + form */}
        <div style={{ display: "flex", flexDirection: "column", gap: 16, minWidth: 0 }}>
          {!parsed && (
            <PasteCard
              raw={rawText} setRaw={setRawText}
              formatting={formatting} onFormat={handleFormat}
            />
          )}

          {warnings.length > 0 && (
            <div className="ui-alert amber">
              <div style={{ fontWeight: 600, marginBottom: 4 }}>Gemini warnings</div>
              {warnings.map((w, i) => (
                <div key={i}>• {w}</div>
              ))}
            </div>
          )}

          {parsed && (
            <FormEditor parsed={parsed} setParsed={setParsed} testType={testType}
                        onReset={() => { setParsed(null); setWarnings([]); }}/>
          )}

          {err && (
            <div className="ui-alert red" style={{ whiteSpace: "pre-wrap" }}>{err}</div>
          )}

          {parsed && (
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", paddingTop: 14,
                          borderTop: "1px solid var(--line)" }}>
              <button className="btn" disabled={saving} onClick={() => handleSave(false)}>
                <window.AppUI.Icon name="penLine" size={15}/>{saving ? "Saving…" : "Save as draft"}
              </button>
              <button className="btn primary" disabled={saving} onClick={() => handleSave(true)}>
                <window.AppUI.Icon name="zap" size={15}/>{saving ? "Saving…" : "Save & make live"}
              </button>
            </div>
          )}
        </div>
      </div>
    </OTScreenShell>
  );
};

/* ---------- Shell wrapping for the screen body ---------- */
const OTScreenShell = ({ children }) => (
  <div className="cx-page" style={{ maxWidth: 1120 }}>
    <div className="cx-page-head" style={{ marginBottom: 22 }}>
      <div>
        <div className="cx-eyebrow">Assessment · Online tests</div>
        <h1 className="cx-h1">Create online test</h1>
        <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>
          Paste raw MCQs · Gemini formats them · review · publish to the student portal.
        </div>
      </div>
    </div>
    {children}
  </div>
);

const OTLabel = ({ children }) => (
  <div className="ui-section-label">{children}</div>
);

const TypeCard = ({ preset, selected, onClick, disabled }) => (
  <div onClick={disabled ? null : onClick}
       role="button" aria-pressed={selected}
       style={{
         border: `1px solid ${selected ? `color-mix(in srgb, ${preset.accent} 55%, transparent)` : "var(--line)"}`,
         borderRadius: "var(--radius-tile)", padding: "14px 16px", cursor: disabled ? "not-allowed" : "pointer",
         background: selected ? `color-mix(in srgb, ${preset.accent} 6%, var(--surface))` : "var(--surface)",
         opacity: disabled && !selected ? 0.5 : 1, transition: "background 120ms, border-color 120ms",
       }}>
    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
      <div style={{ width: 8, height: 8, borderRadius: "50%", background: preset.accent }}/>
      <div style={{ color: "var(--ink-0)", fontSize: 14, fontWeight: 600 }}>{preset.label}</div>
      {selected && <span style={{ marginLeft: "auto", color: "var(--ink-1)" }}><window.AppUI.Icon name="checkCircle" size={15}/></span>}
    </div>
    <div style={{ color: "var(--ink-2)", fontSize: 12.5, marginBottom: 6 }}>{preset.tagline}</div>
    <div style={{ color: "var(--ink-3)", fontSize: 12, lineHeight: 1.45 }}>{preset.detail}</div>
  </div>
);

/* ---------- Paste card ---------- */
const PasteCard = ({ raw, setRaw, formatting, onFormat }) => (
  <window.AppUI.Card title="Paste MCQs"
    sub="Free-text — Gemini will identify questions, options, and the correct answer if marked.">
    <textarea className="textarea"
      value={raw} onChange={(e) => setRaw(e.target.value)}
      placeholder={`Example:\n\n1. Which gas is most abundant in Earth's atmosphere?\n(A) Oxygen\n(B) Nitrogen  *\n(C) Carbon dioxide\n(D) Argon\n\n2. ...`}
      style={{ width: "100%", minHeight: 240, fontFamily: "var(--font-mono)", fontSize: 13, boxSizing: "border-box" }}
    />
    <div style={{ display: "flex", justifyContent: "flex-end", marginTop: 14 }}>
      <button className="btn primary" disabled={formatting || !raw.trim()} onClick={onFormat}>
        <window.AppUI.Icon name="sparkle" size={15}/>{formatting ? "Formatting…" : "Format with Gemini"}
      </button>
    </div>
  </window.AppUI.Card>
);

/* ---------- Form editor ---------- */
const FormEditor = ({ parsed, setParsed, testType, onReset }) => {
  const classSections = window.APP?.CLASS_SECTIONS || [];
  const subjects = window.APP?.SUBJECTS || [];
  const classLevels = Array.from(new Set(classSections.map(cs => cs.class_level))).sort();
  const isDescriptive = testType === "descriptive";

  const set = (path, value) => {
    setParsed((prev) => {
      const next = JSON.parse(JSON.stringify(prev));
      const keys = path.split(".");
      let node = next;
      for (let i = 0; i < keys.length - 1; i++) {
        const k = keys[i];
        node = /^\d+$/.test(k) ? node[Number(k)] : node[k];
      }
      const last = keys[keys.length - 1];
      if (/^\d+$/.test(last)) node[Number(last)] = value;
      else node[last] = value;
      return next;
    });
  };

  const setCorrect = (si, qi, oi) => {
    setParsed((prev) => {
      const next = JSON.parse(JSON.stringify(prev));
      next.sections[si].questions[qi].options.forEach((o, idx) => o.is_correct = (idx === oi));
      return next;
    });
  };

  const addQuestion = (si) => {
    setParsed((prev) => {
      const next = JSON.parse(JSON.stringify(prev));
      const sec = next.sections[si];
      sec.questions.push({
        q_no: sec.questions.length + 1, text: "",
        marks: sec.questions[0]?.marks ?? (isDescriptive ? 5 : 1),
        options: isDescriptive
          ? []
          : ["A","B","C","D"].map((l, i) => ({ letter: l, text: "", is_correct: i === 0 })),
      });
      return next;
    });
  };

  const delQuestion = (si, qi) => {
    setParsed((prev) => {
      const next = JSON.parse(JSON.stringify(prev));
      next.sections[si].questions.splice(qi, 1);
      // Renumber q_no.
      next.sections[si].questions.forEach((q, i) => q.q_no = i + 1);
      return next;
    });
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      {/* Meta block */}
      <window.AppUI.Card title="Test details"
        action={<button className="btn sm" onClick={onReset} title="Discard and paste again">
          <window.AppUI.Icon name="refresh" size={14}/>Reset
        </button>}>
        <div className="ot-2col">
          <Field label="Title" required>
            <Input value={parsed.title || ""} onChange={(v) => set("title", v)}/>
          </Field>
          <Field label="Class" required>
            <Dropdown value={parsed.className || ""} placeholder="Select class"
                      options={classLevels}
                      onChange={(v) => {
                        // Reset section set to the first available section so
                        // the chip row isn't empty after the class change.
                        const first = classSections.find(cs => cs.class_level === v);
                        setParsed(prev => ({
                          ...prev, className: v,
                          class_section_ids: first ? [first.id] : [],
                        }));
                      }}/>
          </Field>
          <Field label="Subject" required>
            <Dropdown value={parsed.subject_id || ""} placeholder="Select subject"
                      options={subjects.map(s => ({ value: s.id, label: s.name }))}
                      onChange={(v) => {
                        const s = subjects.find(x => x.id === v);
                        setParsed(prev => ({ ...prev, subject_id: v, subject: s?.name || "" }));
                      }}/>
          </Field>
          <div style={{ gridColumn: "1 / span 2" }}>
            <Field label="Sections — tap to add (one test can target several)" required>
              <window.AppUI.SectionChips classLevel={parsed.className}
                selectedIds={parsed.class_section_ids || []}
                onChange={(ids) => setParsed(prev => ({ ...prev, class_section_ids: ids }))}/>
            </Field>
          </div>
          {/* Chapter + topic dropdowns sourced from the admin catalog (see
              screen-manual.jsx for the shared picker). Plays nicely with the
              existing `parsed.topic` / `parsed.chapter` text fields — the
              picker reads + writes through them. The wrapper just adapts
              {meta,setMeta} → {parsed,setParsed} so the existing component
              can be reused unchanged. */}
          <window.ChapterTopicFields
            meta={parsed}
            setMeta={(next) => setParsed(next)}
            subjects={subjects}/>
          <Field label="Scheduled date">
            <Input type="date" value={parsed.scheduled_date || ""}
                   onChange={(v) => set("scheduled_date", v || null)}/>
          </Field>
        </div>
      </window.AppUI.Card>

      {/* Sections */}
      {(parsed.sections || []).map((sec, si) => (
        <div key={si} className="cx-card">
          <div className="cx-card-head" style={{ alignItems: "center" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1, minWidth: 0 }}>
              <span className="cx-card-title" style={{ whiteSpace: "nowrap" }}>Section {sec.label}</span>
              <input className="input" value={sec.title || ""} placeholder="Optional section title"
                     onChange={(e) => set(`sections.${si}.title`, e.target.value)}
                     style={{ flex: 1, minWidth: 0 }}/>
            </div>
            <window.AppUI.StatusBadge tone="grey" icon={false}>{sec.questions.length} questions</window.AppUI.StatusBadge>
          </div>

          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {sec.questions.map((q, qi) => (
              <QuestionEditor key={qi} q={q} si={si} qi={qi} set={set}
                              isDescriptive={isDescriptive}
                              setCorrect={setCorrect} onDelete={() => delQuestion(si, qi)}/>
            ))}
          </div>

          <button className="btn sm" onClick={() => addQuestion(si)}
                  style={{ marginTop: 12 }}><window.AppUI.Icon name="plus" size={14}/>Add question</button>
        </div>
      ))}
    </div>
  );
};

/* ---------- Image upload helper ---------- */
async function uploadImage(file) {
  if (!file) return null;
  if (!/^image\//.test(file.type)) throw new Error("Not an image file");
  if (file.size > 5 * 1024 * 1024) throw new Error("Image is larger than 5 MB");
  const form = new FormData();
  form.append("file", file, file.name);
  const r = await fetch(window.AppApi.base + "/online-tests/upload-image", { method: "POST", body: form });
  if (!r.ok) throw new Error(`upload ${r.status}: ${await r.text()}`);
  return (await r.json()).url;
}

const OT_THUMB_X = {
  position: "absolute", top: -7, right: -7, width: 20, height: 20, borderRadius: "50%",
  border: "1px solid var(--line-strong)", background: "var(--surface)", color: "var(--red)",
  display: "grid", placeItems: "center", cursor: "pointer", padding: 0,
};

/* ---------- Multi-image list (used for question + solution images) ---------- */
const ImageList = ({ label, urls, onAdd, onRemove }) => {
  const [busy, setBusy] = React.useState(false);
  const inputRef = React.useRef(null);
  const list = Array.isArray(urls) ? urls : [];

  const pick = async (file) => {
    if (!file) return;
    setBusy(true);
    try { onAdd(await uploadImage(file)); }
    catch (e) { alert("Upload failed: " + (e?.message || e)); }
    finally { setBusy(false); if (inputRef.current) inputRef.current.value = ""; }
  };

  return (
    <div style={{ marginTop: 10 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }}>
        <span style={{ fontSize: 12.5, color: "var(--ink-2)" }}>{label}</span>
        <button type="button" className="btn xs" disabled={busy}
                onClick={() => inputRef.current?.click()}>
          <window.AppUI.Icon name="upload" size={12}/>{busy ? "Uploading…" : "Image"}
        </button>
        <input ref={inputRef} type="file" accept="image/png,image/jpeg,image/webp,image/gif"
               style={{ display: "none" }}
               onChange={(e) => pick(e.target.files?.[0])}/>
      </div>
      {list.length > 0 && (
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
          {list.map((src, i) => (
            <div key={i} style={{ position: "relative", border: "1px solid var(--line)", borderRadius: "var(--radius-ctl)", padding: 3, background: "var(--surface)" }}>
              <img src={src} alt="" style={{ display: "block", maxHeight: 80, maxWidth: 140, borderRadius: 5 }}/>
              <button type="button" title="Remove" aria-label="Remove image"
                      onClick={() => onRemove(i)} style={OT_THUMB_X}>
                <window.AppUI.Icon name="x" size={11}/>
              </button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

/* ---------- Single-image slot (per option) ---------- */
const OptionImage = ({ url, onChange }) => {
  const [busy, setBusy] = React.useState(false);
  const inputRef = React.useRef(null);

  const pick = async (file) => {
    if (!file) return;
    setBusy(true);
    try { onChange(await uploadImage(file)); }
    catch (e) { alert("Upload failed: " + (e?.message || e)); }
    finally { setBusy(false); if (inputRef.current) inputRef.current.value = ""; }
  };

  if (url) {
    return (
      <div style={{ position: "relative", marginLeft: 4 }}>
        <img src={url} alt="" style={{ display: "block", height: 30, borderRadius: 5, border: "1px solid var(--line)" }}/>
        <button type="button" title="Remove" aria-label="Remove option image" onClick={() => onChange(null)}
                style={{ ...OT_THUMB_X, width: 16, height: 16, top: -6, right: -6 }}>
          <window.AppUI.Icon name="x" size={9}/>
        </button>
      </div>
    );
  }
  return (
    <>
      <button type="button" className="btn sm icon-only" disabled={busy}
              onClick={() => inputRef.current?.click()}
              title="Attach option image" aria-label="Attach option image">
        {busy ? "…" : <window.AppUI.Icon name="upload" size={13}/>}
      </button>
      <input ref={inputRef} type="file" accept="image/png,image/jpeg,image/webp,image/gif"
             style={{ display: "none" }}
             onChange={(e) => pick(e.target.files?.[0])}/>
    </>
  );
};

const QuestionEditor = ({ q, si, qi, set, setCorrect, onDelete, isDescriptive }) => {
  const imgs = q.images || { question: [], solution: [] };
  const setImages = (next) => set(`sections.${si}.questions.${qi}.images`, next);
  const addQImage = (url) => setImages({ ...imgs, question: [...(imgs.question || []), url] });
  const rmQImage = (i)   => setImages({ ...imgs, question: (imgs.question || []).filter((_, k) => k !== i) });
  const addSImage = (url) => setImages({ ...imgs, solution: [...(imgs.solution || []), url] });
  const rmSImage = (i)   => setImages({ ...imgs, solution: (imgs.solution || []).filter((_, k) => k !== i) });
  const options = Array.isArray(q.options) ? q.options : [];

  return (
    <div style={{ border: "1px solid var(--line)", borderRadius: "var(--radius-tile)", padding: 14,
                  background: "var(--bg-1)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
        <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink-0)" }}>Q{q.q_no}</span>
        <input className="input" type="number" value={q.marks ?? 1} min={1} step={0.25}
               onChange={(e) => set(`sections.${si}.questions.${qi}.marks`, Number(e.target.value))}
               style={{ width: 72, minHeight: 28, height: 28 }} aria-label="Marks"/>
        <span style={{ fontSize: 12.5, color: "var(--ink-3)" }}>marks</span>
        <button className="ui-iconbtn sm" onClick={onDelete} title="Delete question" aria-label="Delete question"
                style={{ marginLeft: "auto", color: "var(--red)" }}>
          <window.AppUI.Icon name="trash" size={14}/>
        </button>
      </div>
      <textarea className="textarea" value={q.text || ""} placeholder="Question text"
                onChange={(e) => set(`sections.${si}.questions.${qi}.text`, e.target.value)}
                style={{ width: "100%", minHeight: 64, boxSizing: "border-box" }}/>

      <ImageList label="Question images" urls={imgs.question} onAdd={addQImage} onRemove={rmQImage}/>

      {isDescriptive ? (
        <div className="ui-alert blue" style={{ marginTop: 10 }}>
          Students will upload photo(s) of their handwritten answer for this question. Set marks above; grade after submission from the Submissions modal.
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 6, marginTop: 10 }}>
          {options.map((o, oi) => (
            <div key={oi} style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <input type="radio" name={`correct-${si}-${qi}`} checked={!!o.is_correct}
                     onChange={() => setCorrect(si, qi, oi)} title="Correct answer"
                     style={{ accentColor: "var(--green-solid)" }}/>
              <span className="mono" style={{ fontSize: 12.5, color: "var(--ink-2)", width: 16 }}>
                {o.letter}.
              </span>
              <input className="input" value={o.text || ""}
                     onChange={(e) => set(`sections.${si}.questions.${qi}.options.${oi}.text`, e.target.value)}
                     placeholder={`Option ${o.letter}`}
                     style={{ flex: 1, minWidth: 0,
                              borderColor: o.is_correct ? "color-mix(in srgb, var(--green-solid) 50%, transparent)" : undefined,
                              background: o.is_correct ? "var(--green-bg)" : undefined }}/>
              <OptionImage url={o.image || null}
                           onChange={(url) => set(`sections.${si}.questions.${qi}.options.${oi}.image`, url)}/>
            </div>
          ))}
        </div>
      )}

      <ImageList label="Solution images" urls={imgs.solution} onAdd={addSImage} onRemove={rmSImage}/>
    </div>
  );
};

const Field = ({ label, required, children }) => (
  <label className="field" style={{ display: "flex", flexDirection: "column", gap: 6 }}>
    <span className="label">
      {label}{required && <span style={{ color: "var(--red)", marginLeft: 3 }}>*</span>}
    </span>
    {children}
  </label>
);

const FIELD_STYLE = { width: "100%", boxSizing: "border-box" };

const Input = ({ value, onChange, placeholder, type = "text" }) => (
  <input className="input" type={type} value={value ?? ""} placeholder={placeholder}
         onChange={(e) => onChange(e.target.value)}
         style={FIELD_STYLE}/>
);

const Dropdown = ({ value, onChange, options, placeholder }) => (
  <select className="select" value={value ?? ""} onChange={(e) => onChange(e.target.value)}
          style={FIELD_STYLE}>
    {placeholder && <option value="" disabled>{placeholder}</option>}
    {options.map((o) => (
      typeof o === "string"
        ? <option key={o} value={o}>{o}</option>
        : <option key={o.value} value={o.value}>{o.label}</option>
    ))}
  </select>
);

/* ---------- Success splash ---------- */
const OTSuccess = ({ id, onBack, onNew }) => (
  <div className="cx-card" style={{ padding: "40px 32px", textAlign: "center" }}>
    <div style={{ width: 52, height: 52, borderRadius: "50%",
                  background: "var(--green-bg)", color: "var(--green)",
                  margin: "0 auto 16px", display: "grid", placeItems: "center" }}>
      <window.AppUI.Icon name="checkCircle" size={24}/>
    </div>
    <div style={{ color: "var(--ink-0)", fontSize: 18, fontWeight: 600, marginBottom: 6 }}>
      Test <span className="mono">{id}</span> saved
    </div>
    <div style={{ fontSize: 13, color: "var(--ink-2)", marginBottom: 22 }}>
      Use the settings button on the test card if you want to tweak the engine config later.
    </div>
    <div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
      <button className="btn" onClick={onBack}><window.AppUI.Icon name="arrowLeft" size={15}/>Back to library</button>
      <button className="btn primary" onClick={onNew}><window.AppUI.Icon name="plus" size={15}/>Create another</button>
    </div>
  </div>
);

window.OnlineTestsScreen = OnlineTestsScreen;
