// Spellstash — the shared deck source picker.
// ONE way to answer "where does this deck come from" across every tool:
// a saved deck in the stash, a pasted list, a Moxfield link, or the whole
// collection. Before this, each tool invented its own control and supported
// a different arbitrary subset, so Can I Build It could not read your own
// decks and List Compare could not take a Moxfield link.
//
// No build step: loaded as its own Babel script AFTER spellstash-auth.jsx
// and BEFORE the page script. Exposes window.ssDeckSource.
//
// The contract every consumer sees is one value object:
//   { mode, name, lines, ready }
// where `lines` is plain "QTY Name" text (one card per line) for every mode
// except 'collection', which carries no lines and means "use my whole stash".
// Consumers only ever read that object, so adding a fifth source later
// touches this file alone.
//
// Analytics stay page-owned: pass onTrack and the surface keeps its own
// permanent event names, same rule as card-popup.jsx.
(() => {
  const { useState, useEffect, useRef, useCallback } = React;

  const T = {
    accent: "var(--cm-accent)",
    accentFg: "var(--cm-accent-fg)",
    accentSoft: "var(--cm-accent-soft)",
    bg: "var(--bg)", bg2: "var(--bg-2)", bg3: "var(--bg-3)",
    line: "var(--line)",
    ink: "var(--ink)", ink2: "var(--ink-2)", ink3: "var(--ink-3)",
    good: "var(--good)",
    sans: "var(--cm-sans)", mono: "var(--cm-mono)",
  };

  const LABELS = {
    decks: "My decks",
    paste: "Paste a list",
    moxfield: "Moxfield",
    collection: "Whole collection",
  };
  // Sources that need an account. Signed out, they explain themselves
  // instead of sitting there disabled and silent.
  const NEEDS_AUTH = { decks: true, collection: true, paste: false, moxfield: false };

  const EMPTY = { mode: null, name: "", lines: "", ready: false };

  // ── data ────────────────────────────────────────────────────────────────
  // Decks the user can pick. Wishlists are not decks you would grade or
  // compare, so they stay out.
  async function fetchDecks() {
    const r = await window.ssAuth.authedFetch("/api/containers");
    if (!r.ok) throw new Error("Could not load your decks.");
    const rows = await r.json();
    return (Array.isArray(rows) ? rows : [])
      .filter((c) => c && c.kind === "deck" && !c.is_wishlist && !c.archived_at)
      .sort((a, b) => String(a.name || "").localeCompare(String(b.name || "")));
  }

  // Names-only export is exactly the "QTY Name" shape every tool parses,
  // aggregated across piles, no set codes to confuse a paste parser.
  async function fetchDeckLines(id) {
    const r = await window.ssAuth.authedFetch(`/api/containers/${id}/export?format=plain`);
    if (!r.ok) throw new Error("Could not read that deck.");
    return (await r.text()).trim();
  }

  // Public endpoint, works signed out, so a stranger can bring a Moxfield
  // deck to any tool.
  async function fetchMoxfield(url) {
    const r = await window.ssAuth.authedFetch("/api/moxfield/list", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ url }),
    });
    const data = await r.json().catch(() => ({}));
    if (!r.ok) throw new Error(data.error || "Could not read that Moxfield deck.");
    const lines = Array.isArray(data.lines) ? data.lines.join("\n") : String(data.lines || "");
    if (!lines.trim()) throw new Error("That deck came back empty.");
    return { name: data.name || "Moxfield deck", lines, commanders: data.commanders || [] };
  }

  // ── the picker ──────────────────────────────────────────────────────────
  function DeckSourcePicker({
    session,
    sources,          // e.g. ["decks","paste","moxfield"] — order is the tab order
    value,            // { mode, name, lines, ready }
    onChange,
    onTrack,
    label,            // optional eyebrow, e.g. "List A"
    placeholder,
    surface,          // string for analytics props
    rows,             // textarea rows
  }) {
    const avail = (sources && sources.length ? sources : ["decks", "paste", "moxfield"])
      .filter((s) => LABELS[s]);
    const signedIn = !!session;

    // First real tab: a signed-in user starts on their own decks, everyone
    // else starts on the first source that works without an account.
    const initial = signedIn
      ? avail[0]
      : (avail.find((s) => !NEEDS_AUTH[s]) || avail[0]);
    const [mode, setMode] = useState(value && value.mode ? value.mode : initial);
    const [decks, setDecks] = useState(null);
    const [deckErr, setDeckErr] = useState(null);
    const [deckId, setDeckId] = useState("");
    const [paste, setPaste] = useState(value && value.mode === "paste" ? value.lines : "");
    const [moxUrl, setMoxUrl] = useState("");
    const [busy, setBusy] = useState(false);
    const [err, setErr] = useState(null);
    const loadedRef = useRef(false);

    const emit = useCallback((next) => { onChange && onChange(next); }, [onChange]);
    const track = useCallback((n, p) => { onTrack && onTrack(n, p); }, [onTrack]);

    // Once a session arrives, move an anonymous visitor onto their decks if
    // that is the tool's preferred source and they have not typed anything.
    useEffect(() => {
      if (!signedIn || loadedRef.current) return;
      if (mode === initial || paste.trim() || moxUrl.trim()) return;
      setMode(initial);
    }, [signedIn]); // eslint-disable-line react-hooks/exhaustive-deps

    // Deck list loads once, lazily, only when the tab is actually open.
    useEffect(() => {
      if (mode !== "decks" || !signedIn || decks || loadedRef.current) return;
      loadedRef.current = true;
      fetchDecks()
        .then((d) => { setDecks(d); setDeckErr(null); })
        .catch((e) => { setDeckErr(e.message); loadedRef.current = false; });
    }, [mode, signedIn, decks]);

    function switchMode(m) {
      setMode(m);
      setErr(null);
      track("SourcePickerMode", { surface: surface || "", mode: m });
      // Switching source clears the resolved value so a stale list can never
      // be submitted under a new mode.
      if (m === "collection") emit({ mode: "collection", name: "My whole collection", lines: "", ready: true });
      else if (m === "paste") emit({ mode: "paste", name: "", lines: paste, ready: !!paste.trim() });
      else emit({ ...EMPTY, mode: m });
    }

    async function pickDeck(id) {
      setDeckId(id);
      if (!id) return emit({ ...EMPTY, mode: "decks" });
      const deck = (decks || []).find((d) => String(d.id) === String(id));
      setBusy(true); setErr(null);
      try {
        const lines = await fetchDeckLines(id);
        if (!lines) throw new Error("That deck has no cards in it yet.");
        emit({ mode: "decks", name: (deck && deck.name) || "My deck", lines, ready: true });
        track("SourcePickerDeck", { surface: surface || "" });
      } catch (e) {
        setErr(e.message);
        emit({ ...EMPTY, mode: "decks" });
      } finally { setBusy(false); }
    }

    async function loadMox() {
      const url = moxUrl.trim();
      if (!url) return;
      setBusy(true); setErr(null);
      try {
        const got = await fetchMoxfield(url);
        // `url` rides along so a consumer can hand the ORIGINAL link to a
        // backend that knows how to read commanders from it. Plain lines
        // cannot say which cards are the commanders.
        emit({ mode: "moxfield", name: got.name, lines: got.lines, url, commanders: got.commanders, ready: true });
        track("SourcePickerMoxfield", { surface: surface || "" });
      } catch (e) {
        setErr(e.message);
        emit({ ...EMPTY, mode: "moxfield" });
      } finally { setBusy(false); }
    }

    function onPaste(text) {
      setPaste(text);
      emit({ mode: "paste", name: "", lines: text, ready: !!text.trim() });
    }

    const pill = (active) => ({
      flex: 1, minHeight: 44, padding: "0 10px", borderRadius: 999, cursor: "pointer",
      border: "2px solid " + (active ? T.accent : T.line),
      background: active ? T.accent : "transparent",
      color: active ? T.accentFg : T.ink2,
      font: "700 13px " + T.sans,
    });
    const field = {
      width: "100%", minHeight: 46, padding: "0 12px", boxSizing: "border-box",
      font: "500 15px " + T.sans, color: T.ink, background: T.bg,
      border: "1px solid " + T.line, borderRadius: 10,
    };

    const signInPrompt = (what) => (
      <div style={{ padding: "14px 2px", font: "500 14px " + T.sans, color: T.ink2 }}>
        <a href={"/login?signup=1&next=" + encodeURIComponent(location.pathname + location.search)}
           style={{ color: T.accent, fontWeight: 700 }}>Sign in free</a>
        {" "}to use {what}. It takes a minute and your stash stays private.
      </div>
    );

    return (
      <div>
        {label && (
          <div style={{ font: "700 11px " + T.mono, letterSpacing: ".08em", textTransform: "uppercase", color: T.ink3, marginBottom: 6 }}>
            {label}
          </div>
        )}

        {avail.length > 1 && (
          <div style={{ display: "flex", gap: ".4rem", marginBottom: ".7rem" }}>
            {avail.map((m) => (
              <button key={m} type="button" onClick={() => switchMode(m)}
                      aria-pressed={mode === m} style={pill(mode === m)}>
                {LABELS[m]}
              </button>
            ))}
          </div>
        )}

        {mode === "decks" && (!signedIn ? signInPrompt("a deck from your stash") : (
          <div>
            {deckErr && <p style={{ color: T.accent, font: "500 13px " + T.sans, margin: "0 0 8px" }}>{deckErr}</p>}
            {!decks && !deckErr && <p style={{ color: T.ink3, font: "500 14px " + T.sans, margin: "6px 0" }}>Loading your decks…</p>}
            {decks && decks.length === 0 && (
              <p style={{ color: T.ink2, font: "500 14px " + T.sans, margin: "6px 0" }}>
                No decks in your stash yet. <a href="/collection" style={{ color: T.accent, fontWeight: 700 }}>Add one</a>, or paste a list instead.
              </p>
            )}
            {decks && decks.length > 0 && (
              <select value={deckId} onChange={(e) => pickDeck(e.target.value)}
                      aria-label="Choose a deck from your stash" style={{ ...field, height: 46 }}>
                <option value="">Choose a deck…</option>
                {decks.map((d) => (
                  <option key={d.id} value={d.id}>
                    {d.name}{d.card_count ? ` (${d.card_count})` : ""}
                  </option>
                ))}
              </select>
            )}
          </div>
        ))}

        {mode === "paste" && (
          <textarea
            value={paste}
            onChange={(e) => onPaste(e.target.value)}
            placeholder={placeholder || "Paste a list. One card per line."}
            rows={rows || 8}
            spellCheck={false}
            style={{ ...field, minHeight: 140, padding: 12, font: "500 14px " + T.mono, lineHeight: 1.5, resize: "vertical" }}
          />
        )}

        {mode === "moxfield" && (
          <div>
            <div style={{ display: "flex", gap: 8 }}>
              <input
                value={moxUrl}
                onChange={(e) => setMoxUrl(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); loadMox(); } }}
                placeholder="https://moxfield.com/decks/…"
                aria-label="Moxfield deck link"
                inputMode="url"
                style={{ ...field, flex: 1 }}
              />
              <button type="button" onClick={loadMox} disabled={busy || !moxUrl.trim()}
                      style={{ minHeight: 46, padding: "0 16px", borderRadius: 10, border: 0,
                               background: T.accent, color: T.accentFg, font: "700 14px " + T.sans,
                               cursor: busy || !moxUrl.trim() ? "default" : "pointer",
                               opacity: busy || !moxUrl.trim() ? 0.55 : 1 }}>
                {busy ? "Loading…" : "Load"}
              </button>
            </div>
            <p style={{ margin: "6px 0 0", font: "500 12px " + T.sans, color: T.ink3 }}>
              Any public Moxfield deck. Private decks stay private.
            </p>
          </div>
        )}

        {mode === "collection" && (!signedIn ? signInPrompt("your whole collection") : (
          <p style={{ margin: "6px 0", font: "500 14px " + T.sans, color: T.ink2 }}>
            Using every card in your stash.
          </p>
        ))}

        {err && <p style={{ color: T.accent, font: "600 13px " + T.sans, margin: "8px 0 0" }}>{err}</p>}

        {value && value.ready && value.name && mode !== "collection" && (
          <p style={{ margin: "8px 0 0", font: "600 13px " + T.sans, color: T.good }}>
            Loaded {value.name}
            {value.lines ? ` (${value.lines.split("\n").filter((l) => l.trim()).length} lines)` : ""}
          </p>
        )}
      </div>
    );
  }

  window.ssDeckSource = { DeckSourcePicker, fetchDecks, fetchDeckLines, fetchMoxfield, EMPTY, LABELS };
})();
