// Can I Build It? — paste any public Moxfield deck link, cross it against
// YOUR stash. FREE for every tier, forever (Rob's Moxfield term: derived
// data never sits behind Pro). Signed out = deck teaser + the sign-in hook;
// signed in = the full owned/where/gap report.
const { useState, useEffect } = React;

const T = {
  sans: "Inter, system-ui, sans-serif",
  serif: "Archivo, Inter, sans-serif",
  mono: "'JetBrains Mono', Menlo, monospace",
  ink: "var(--ink, #17130c)", ink2: "var(--ink-2, #3d3629)", ink3: "var(--ink-3, #8a7f6d)",
  bg: "var(--bg, #faf6ee)", bg2: "var(--bg-2, #fffdf8)", bg3: "var(--bg-3, #efe9dc)",
  line: "var(--line, #e3dccb)", accent: "#d05d25", accentFg: "#fff", good: "#3f7d4e",
};
const card = { background: T.bg2, border: "1px solid " + T.line, borderRadius: 14, padding: 16 };
const URL_KEY = "spellstash.canbuild.url";

function track(name, props) {
  try { if (window.plausible) window.plausible(name, props ? { props } : undefined); } catch (e) { /* no-op */ }
}

function Row({ c }) {
  const loc = Array.isArray(c.locations) && c.locations.length ? c.locations[0] : null;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "8px 10px", borderRadius: 12, background: c.owned ? T.bg2 : "transparent", border: "1px solid " + (c.owned ? "rgba(23,19,12,0.10)" : "transparent"), position: "relative" }}>
      {c.owned && <span style={{ position: "absolute", left: 0, top: 9, bottom: 9, width: 3, borderRadius: 2, background: T.good }} />}
      {c.image_normal
        ? <img src={c.image_normal} alt="" loading="lazy" style={{ width: 42, height: 58, borderRadius: 4, objectFit: "cover", background: T.bg3, flexShrink: 0 }} />
        : <div style={{ width: 42, height: 58, borderRadius: 4, background: T.bg3, flexShrink: 0 }} />}
      <div style={{ minWidth: 0, flex: 1 }}>
        <div style={{ font: "600 14.5px " + T.sans, color: T.ink, display: "flex", alignItems: "center", gap: 6 }}>
          <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{c.qty > 1 ? c.qty + "× " : ""}{c.name}</span>
          {c.is_commander && <span style={{ font: "700 9px " + T.mono, letterSpacing: "0.06em", color: T.accent, border: "1px solid " + T.accent, borderRadius: 999, padding: "2px 7px", flexShrink: 0 }}>CMDR</span>}
        </div>
        <div style={{ font: "500 11.5px " + T.mono, color: c.owned ? T.good : T.ink3, marginTop: 2, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
          {c.owned ? "✓ in your stash" + (loc ? " · " + loc.container_name : "") : "you need this one"}
        </div>
      </div>
      {!c.owned && c.buy_url && (
        <a href={c.buy_url} target="_blank" rel="noopener noreferrer" aria-label={"Buy " + c.name + " at Card Kingdom"}
          onClick={() => track("CanBuildBuyClick", { card: c.name })}
          style={{ font: "700 13px " + T.mono, color: T.accent, textDecoration: "none", flexShrink: 0 }}>
          {typeof c.ck_price === "number" ? "$" + c.ck_price.toFixed(2) : "buy"}
        </a>
      )}
      {!c.owned && !c.buy_url && typeof c.ck_price === "number" && (
        <span style={{ font: "700 13px " + T.mono, color: T.ink2, flexShrink: 0 }}>${c.ck_price.toFixed(2)}</span>
      )}
    </div>
  );
}

function CanIBuildItApp() {
  const [session, sessionLoading] = window.ssAuth.useSession();
  const [url, setUrl] = useState(() => {
    try { return localStorage.getItem(URL_KEY) || ""; } catch (e) { return ""; }
  });
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);
  const [teaser, setTeaser] = useState(null); // signed-out: /list result
  const [report, setReport] = useState(null); // signed-in: /can-build result

  const run = async (u) => {
    const target = (u || url).trim();
    if (!target || busy) return;
    setBusy(true); setError(null); setTeaser(null); setReport(null);
    try { localStorage.setItem(URL_KEY, target); } catch (e) { /* best effort */ }
    try {
      if (session) {
        const r = await window.ssAuth.authedFetch("/api/moxfield/can-build", {
          method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: target }),
        });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) { setError(j.error || "Could not check that deck."); return; }
        setReport(j);
        track("CanBuildReport", { owned: j.totals.owned, total: j.totals.cards });
      } else {
        const r = await fetch("/api/moxfield/list", {
          method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: target }),
        });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) { setError(j.error || "Could not read that deck."); return; }
        setTeaser(j);
        track("CanBuildTeaser", {});
      }
    } catch (e) {
      setError("Could not reach the deck. Try again in a moment.");
    } finally {
      setBusy(false);
    }
  };

  // Back from sign-in with a stashed URL: run it automatically. Running a
  // LOOKUP on return is the promised action, not a mutation.
  useEffect(() => {
    if (sessionLoading || !session) return;
    let stashed = "";
    try { stashed = localStorage.getItem(URL_KEY) || ""; } catch (e) { /* no-op */ }
    if (stashed && new URLSearchParams(window.location.search).get("resume") === "1") {
      run(stashed);
    }
  }, [session, sessionLoading]);

  const goImport = () => {
    try { sessionStorage.setItem("spellstash.import.moxfield", url.trim()); } catch (e) { /* best effort */ }
    track("CanBuildImportClick", {});
    window.location.href = "/collection?manage=import";
  };
  const goBrew = () => {
    try { sessionStorage.setItem("spellstash.brewer.paste", url.trim()); } catch (e) { /* best effort */ }
    track("CanBuildBrewClick", {});
    window.location.href = "/bracketizer";
  };
  const goGrade = () => {
    try { sessionStorage.setItem("spellstash.bracketcheck.handoff", JSON.stringify({ list: url.trim(), commander: "" })); } catch (e) { /* best effort */ }
    track("CanBuildGradeClick", {});
    window.location.href = "/commander-bracket-checker";
  };

  const gap = report ? report.cards.filter((c) => !c.owned) : [];
  const owned = report ? report.cards.filter((c) => c.owned) : [];

  return (
    <window.ssShell.AppShell active="canibuildit" session={session}>
      <main className="cm-radar" style={{ maxWidth: 860, margin: "0 auto", padding: "0 16px" }}>
        <header className="cm-radar-head">
          <div className="cm-radar-head-main">
            <div className="cm-eyebrow">Can I Build It? <span className="cm-new-chip">NEW</span></div>
            <h1 className="cm-h1 cm-h1--sm">Can you build that deck?</h1>
            <p className="cm-radar-lead">
              Paste any public Moxfield deck link. See which cards already live
              in your stash, where each copy is, and what the missing ones cost.
            </p>
          </div>
        </header>

        <div style={{ ...card, marginTop: 16 }}>
          <input
            value={url}
            onChange={(e) => setUrl(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") run(); }}
            placeholder="https://moxfield.com/decks/…"
            aria-label="Moxfield deck link"
            inputMode="url"
            style={{ width: "100%", height: 46, padding: "0 12px", font: "500 15px " + T.sans, color: T.ink, background: T.bg, border: "1px solid " + T.line, borderRadius: 10, boxSizing: "border-box" }}
          />
          <button type="button" onClick={() => run()} disabled={busy || !url.trim()}
            style={{ width: "100%", height: 46, marginTop: 10, borderRadius: 10, border: "none", background: !busy && url.trim() ? T.accent : T.bg3, color: !busy && url.trim() ? T.accentFg : T.ink3, font: "700 15px " + T.sans, cursor: !busy && url.trim() ? "pointer" : "default" }}>
            {busy ? "Reading the deck…" : "Can I build it?"}
          </button>
          {error && <div style={{ font: "500 13.5px " + T.sans, color: "#b3402a", marginTop: 10 }}>{error}</div>}
        </div>

        {teaser && (
          <div style={{ ...card, marginTop: 12, borderLeft: "3px solid " + T.accent }}>
            <div style={{ fontFamily: T.serif, fontSize: "1.12rem", fontWeight: 700, color: T.ink }}>
              {teaser.name || "That deck"} · {teaser.card_count} cards
            </div>
            {teaser.commanders && teaser.commanders.length > 0 && (
              <div style={{ font: "500 12px " + T.mono, color: T.ink3, marginTop: 2 }}>Commander: {teaser.commanders.join(" + ")}</div>
            )}
            <p style={{ font: "400 14px " + T.sans, color: T.ink2, margin: "8px 0 10px" }}>
              Sign in free and your collection lights this list up: which of these {teaser.card_count} cards you already own, where every copy lives, and the bill for the rest.
            </p>
            <a href={"/login?next=" + encodeURIComponent("/can-i-build-it?resume=1")}
              style={{ display: "inline-block", padding: "11px 18px", background: T.accent, color: T.accentFg, borderRadius: 10, font: "700 14px " + T.sans, textDecoration: "none" }}>
              See what I own · free
            </a>
          </div>
        )}

        {report && (
          <>
            <div style={{ ...card, marginTop: 12, borderLeft: "3px solid " + T.accent }}>
              <div style={{ fontFamily: T.serif, fontSize: "1.12rem", fontWeight: 700, color: T.ink }}>
                You own {report.totals.owned} of {report.totals.cards}. The gap runs ${report.totals.gap_cost.toLocaleString()}.
              </div>
              <div style={{ color: T.ink2, fontSize: "0.9rem", marginTop: "0.35rem" }}>
                {report.deck_name || "This deck"}{report.commanders.length > 0 ? " · " + report.commanders.join(" + ") : ""}
                {report.totals.gap_priced < report.totals.unowned ? " · " + (report.totals.unowned - report.totals.gap_priced) + " missing cards have no Card Kingdom price" : ""}
              </div>
              <div aria-hidden="true" style={{ height: 8, background: T.bg3, borderRadius: 4, marginTop: 10, overflow: "hidden" }}>
                <i style={{ display: "block", height: "100%", background: T.good, width: Math.round((100 * report.totals.owned) / Math.max(1, report.totals.cards)) + "%" }} />
              </div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 12 }}>
                <button type="button" className="cm-btn cm-btn--primary" onClick={goImport} style={{ minHeight: 44, textTransform: "none", letterSpacing: 0 }}>Import it as a deck</button>
                <button type="button" className="cm-btn cm-btn--ghost" onClick={goBrew} style={{ minHeight: 44, textTransform: "none", letterSpacing: 0 }}>Brew the upgrade</button>
                <button type="button" className="cm-btn cm-btn--ghost" onClick={goGrade} style={{ minHeight: 44, textTransform: "none", letterSpacing: 0 }}>Grade the bracket</button>
              </div>
            </div>

            {report.cards.some((c) => !c.image_normal) && (
              <p style={{ font: "500 12px " + T.mono, color: T.ink3, margin: "10px 2px 0" }}>
                Some card images are still warming up. This deck's first look loads the art; run it again and they fill in.
              </p>
            )}
            {gap.length > 0 && (
              <div style={{ ...card, marginTop: 12, padding: "10px 10px" }}>
                <div style={{ font: "700 11px " + T.mono, letterSpacing: "0.08em", textTransform: "uppercase", color: T.ink3, padding: "4px 6px 8px" }}>
                  The gap · {gap.length} card{gap.length === 1 ? "" : "s"} · ${report.totals.gap_cost.toLocaleString()}
                </div>
                {gap.map((c) => <Row key={c.name} c={c} />)}
              </div>
            )}
            {owned.length > 0 && (
              <div style={{ ...card, marginTop: 12, padding: "10px 10px" }}>
                <div style={{ font: "700 11px " + T.mono, letterSpacing: "0.08em", textTransform: "uppercase", color: T.ink3, padding: "4px 6px 8px" }}>
                  Already yours · {owned.length}
                </div>
                {owned.map((c) => <Row key={c.name} c={c} />)}
              </div>
            )}
          </>
        )}

        <p className="cm-radar-note" style={{ marginTop: 18 }}>
          Deck data read from Moxfield with permission; Spellstash is not affiliated with Moxfield.
          Spellstash is unaffiliated with Wizards of the Coast. Magic: The Gathering and all card data are property of Wizards of the Coast LLC.
        </p>
      </main>
    </window.ssShell.AppShell>
  );
}

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