import "./fabula-ultima-sheet.css";

// ── STATE ──────────────────────────────────────────
let urlMode = false;
let level = 1;
let fpCount = 0;
let primaryClasses = [];
let otherClasses = [];
let spells = [];
let bonds = [
  { name: "", feelings: [] },
  { name: "", feelings: [] },
  { name: "", feelings: [] },
  { name: "", feelings: [] },
  { name: "", feelings: [] },
  { name: "", feelings: [] },
];

const STATUSES = ["Slow", "Enraged", "Dazed", "Weak", "Poisoned", "Shaken"];
const FEELINGS = [
  "Admiration",
  "Inferiority",
  "Loyalty",
  "Mistrust",
  "Affection",
  "Hatred",
];

// ── TABS ───────────────────────────────────────────
function switchTab(tab) {
  document
    .querySelectorAll(".tab")
    .forEach((t) => t.classList.remove("active"));
  document
    .querySelectorAll(".page")
    .forEach((p) => p.classList.remove("active"));
  event.currentTarget.classList.add("active");
  document.getElementById("page-" + tab).classList.add("active");
}

// ── INIT ───────────────────────────────────────────
async function init() {
  const savedTheme =
    localStorage.getItem("fabulaUltimaTheme") ||
    (window.matchMedia("(prefers-color-scheme: light)").matches
      ? "light"
      : "dark");
  document.getElementById("themeToggle").textContent =
    savedTheme === "light" ? "☾ Dark" : "☀ Light";
  renderStatuses();
  renderFP();
  renderBonds();
  renderPrimaryClasses();
  renderOtherClasses();
  renderSpells();
  updateXPBar();
  if (!(await tryLoadFromURL())) tryAutoLoad();
}

// ── URL STATE ──────────────────────────────────────
async function compressToBase64(str) {
  const stream = new CompressionStream("deflate-raw");
  const writer = stream.writable.getWriter();
  writer.write(new TextEncoder().encode(str));
  writer.close();
  const buf = await new Response(stream.readable).arrayBuffer();
  const bytes = new Uint8Array(buf);
  let binary = "";
  for (let i = 0; i < bytes.length; i++)
    binary += String.fromCharCode(bytes[i]);
  return btoa(binary);
}

async function decompressFromBase64(b64) {
  try {
    const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
    const stream = new DecompressionStream("deflate-raw");
    const writer = stream.writable.getWriter();
    writer.write(bytes);
    writer.close();
    const buf = await new Response(stream.readable).arrayBuffer();
    return new TextDecoder().decode(buf);
  } catch {
    // Fall back to legacy uncompressed URLs
    return decodeURIComponent(escape(atob(b64)));
  }
}

async function tryLoadFromURL() {
  const encoded = new URLSearchParams(window.location.search).get("c");
  if (!encoded) return false;
  try {
    const json = await decompressFromBase64(encoded);
    applyData(JSON.parse(json));
    urlMode = true;
    document.getElementById("urlBanner").style.display = "block";
    return true;
  } catch (e) {
    console.warn("Could not load state from URL:", e);
    return false;
  }
}

// ── STATUS EFFECTS ─────────────────────────────────
function renderStatuses() {
  const g = document.getElementById("statusGrid");
  g.innerHTML = "";
  STATUSES.forEach((s) => {
    const el = document.createElement("div");
    el.className = "status-item";
    el.dataset.status = s;
    el.onclick = () => {
      el.classList.toggle("active-status");
      el.querySelector(".status-check").textContent = el.classList.contains(
        "active-status",
      )
        ? "✗"
        : "";
    };
    el.innerHTML = `<div class="status-check"></div><div class="status-label">${s}</div>`;
    g.appendChild(el);
  });
}

// ── FABULA POINTS ──────────────────────────────────
function renderFP() {
  fpCount = parseInt(document.getElementById("fpCount").value) || 0;
  const pips = document.getElementById("fpPips");
  const total = Math.max(10, fpCount);
  pips.innerHTML = "";
  for (let i = 0; i < total; i++) {
    const pip = document.createElement("div");
    pip.className = "fp-pip" + (i < fpCount ? " filled" : "");
    pip.onclick = () => {
      const newVal = i < fpCount ? i : i + 1;
      document.getElementById("fpCount").value = newVal;
      renderFP();
    };
    pips.appendChild(pip);
  }
}

// ── BONDS ──────────────────────────────────────────
function renderBonds() {
  const container = document.getElementById("bondsContainer");
  container.innerHTML = "";
  bonds.forEach((bond, idx) => {
    const el = document.createElement("div");
    el.className = "bond-block";
    el.innerHTML = `
      <div class="bond-header">
        <div class="bond-num">${idx + 1}</div>
        <input type="text" placeholder="Bond target name…" value="${bond.name}" oninput="bonds[${idx}].name=this.value">
      </div>
      <div class="bond-feelings">
        ${FEELINGS.map(
          (f) => `
          <div class="bond-feeling${bond.feelings.includes(f) ? " active" : ""}" onclick="toggleFeeling(${idx},'${f}',this)">
            <div class="bond-feeling-box">${bond.feelings.includes(f) ? "✓" : ""}</div>
            <span>${f}</span>
          </div>`,
        ).join("")}
      </div>`;
    container.appendChild(el);
  });
}

function toggleFeeling(bondIdx, feeling, el) {
  const bond = bonds[bondIdx];
  if (bond.feelings.includes(feeling)) {
    bond.feelings = bond.feelings.filter((f) => f !== feeling);
    el.classList.remove("active");
    el.querySelector(".bond-feeling-box").textContent = "";
  } else {
    bond.feelings.push(feeling);
    el.classList.add("active");
    el.querySelector(".bond-feeling-box").textContent = "✓";
  }
}

// ── LEVEL ──────────────────────────────────────────
function adjustLevel(delta) {
  level = Math.max(1, Math.min(50, level + delta));
  document.getElementById("levelDisplay").textContent = level;
}

// ── XP BAR ─────────────────────────────────────────
function updateXPBar() {
  const xp = parseInt(document.getElementById("xpCurrent").value) || 0;
  const pct = Math.min((xp % 10) * 10, 100);
  document.getElementById("xpBar").style.width = pct + "%";
  document.getElementById("xpVal").textContent = xp + " XP";
}

// ── STAT CALC ──────────────────────────────────────
function recalcStats() {
  /* auto-calc on keyup */
}

function calcHP() {
  const mig = parseInt(document.getElementById("mig-base").value) || 6;
  const max = mig * 5 + level;
  document.getElementById("hpMax").value = max;
  if (!document.getElementById("hpCur").value)
    document.getElementById("hpCur").value = max;
  updateCrisis();
}

function calcMP() {
  const wlp = parseInt(document.getElementById("wlp-base").value) || 6;
  const max = wlp * 5 + level;
  document.getElementById("mpMax").value = max;
  if (!document.getElementById("mpCur").value)
    document.getElementById("mpCur").value = max;
}

function updateCrisis() {
  const max = parseInt(document.getElementById("hpMax").value) || 0;
  const cur = parseInt(document.getElementById("hpCur").value) || 0;
  const badge = document.getElementById("crisisBadge");
  badge.style.display =
    max > 0 && cur <= Math.floor(max / 2) ? "block" : "none";
}

// ── MARTIAL ────────────────────────────────────────
function toggleMartial(el) {
  el.classList.toggle("checked");
  el.querySelector(".martial-box").textContent = el.classList.contains(
    "checked",
  )
    ? "✓"
    : "";
}

// ── DISCIPLINES ────────────────────────────────────
function toggleDisc(el) {
  el.classList.toggle("checked");
  el.querySelector(".disc-box").textContent = el.classList.contains("checked")
    ? "✓"
    : "";
}

// ── CLASSES ────────────────────────────────────────
function classBlockHTML(cls, idx, type) {
  return `
    <div class="class-block" id="${type}-class-${idx}">
      <div class="class-header">
        <input type="text" placeholder="Class name…" value="${cls.name || ""}" oninput="${type}Classes[${idx}].name=this.value">
        <input type="text" placeholder="Free benefits…" value="${cls.benefits || ""}" oninput="${type}Classes[${idx}].benefits=this.value">
      </div>
      <div class="class-skills">
        <textarea placeholder="Skill information…" oninput="${type}Classes[${idx}].skills=this.value">${cls.skills || ""}</textarea>
      </div>
      <div style="padding:6px 10px; border-top:1px solid var(--border); display:flex; justify-content:flex-end;">
        <button class="spell-del-btn" onclick="removeClass('${type}',${idx})">✕ Remove</button>
      </div>
    </div>`;
}

function renderPrimaryClasses() {
  document.getElementById("primaryClassContainer").innerHTML = primaryClasses
    .map((c, i) => classBlockHTML(c, i, "primary"))
    .join("");
}

function renderOtherClasses() {
  document.getElementById("otherClassContainer").innerHTML = otherClasses
    .map((c, i) => classBlockHTML(c, i, "other"))
    .join("");
}

function addPrimaryClass() {
  primaryClasses.push({});
  renderPrimaryClasses();
}
function addOtherClass() {
  otherClasses.push({});
  renderOtherClasses();
}
function removeClass(type, idx) {
  if (type === "primary") {
    primaryClasses.splice(idx, 1);
    renderPrimaryClasses();
  } else {
    otherClasses.splice(idx, 1);
    renderOtherClasses();
  }
}

// ── SPELLS ─────────────────────────────────────────
function renderSpells() {
  const tbody = document.getElementById("spellsBody");
  tbody.innerHTML = spells
    .map(
      (s, i) => `
    <tr>
      <td class="spell-name-col">
        <input type="text" placeholder="Spell / Arcana name…" value="${s.name || ""}" oninput="spells[${i}].name=this.value">
        <textarea placeholder="Notes / effect description…" oninput="spells[${i}].notes=this.value">${s.notes || ""}</textarea>
      </td>
      <td class="spell-mp-col"><input type="number" placeholder="0" value="${s.mp || ""}" oninput="spells[${i}].mp=this.value" style="min-height:32px;"></td>
      <td class="spell-targets-col"><input type="text" placeholder="Target(s)…" value="${s.targets || ""}" oninput="spells[${i}].targets=this.value"></td>
      <td class="spell-dur-col"><input type="text" placeholder="Duration…" value="${s.duration || ""}" oninput="spells[${i}].duration=this.value"></td>
      <td class="spell-del-col"><button class="spell-del-btn" onclick="removeSpell(${i})">✕</button></td>
    </tr>`,
    )
    .join("");
}

function addSpell() {
  spells.push({});
  renderSpells();
}
function removeSpell(i) {
  spells.splice(i, 1);
  renderSpells();
}

// ── SAVE / LOAD ────────────────────────────────────
// Short key legend (serialized form only; in-memory objects use full names):
//   n=name, pn=pronouns, id=identity, th=theme, og=origin, tr=traits
//   lv=level, xp=xp, z=zenit
//   im=initMod, df=defense, md=magDef
//   dxb=dexBase, dxc=dexCur, inb=insBase, inc=insCur
//   mgb=migBase, mgc=migCur, wpb=wlpBase, wpc=wlpCur
//   hx=hpMax, hc=hpCur, mx=mpMax, mc=mpCur, ix=ipMax, ic=ipCur
//   fp=fp, bp=backpack
//   acn=accName, acd=accDesc, amn=armName, amd=armDesc
//   mhn=mhName, mhd=mhDesc, ohn=ohName, ohd=ohDesc
//   hs=heroicSkills, rn=ritualsNotes
//   sa=statusesActive, ma=martialChecked, da=disciplinesChecked
//   bo=bonds, pc=primaryClasses, oc=otherClasses, sp=spells
// Nested bonds:        n=name, f=feelings
// Nested classes:      n=name, b=benefits, s=skills
// Nested spells:       n=name, nt=notes, mp=mp, tg=targets, dr=duration
function collectData() {
  const get = (id) => {
    const el = document.getElementById(id);
    return el ? el.value : "";
  };
  const sa = [...document.querySelectorAll(".status-item.active-status")].map(
    (el) => el.dataset.status,
  );
  const ma = [...document.querySelectorAll(".martial-item.checked")].map(
    (el) => el.querySelector("span").textContent,
  );
  const da = [...document.querySelectorAll(".disc-item.checked")].map(
    (el) => el.querySelector("span").textContent,
  );

  return {
    n: get("charName"),
    pn: get("charPronouns"),
    id: get("charIdentity"),
    th: get("charTheme"),
    og: get("charOrigin"),
    tr: get("charTraits"),
    lv: level,
    xp: get("xpCurrent"),
    z: get("zenit"),
    im: get("initMod"),
    df: get("defense"),
    md: get("magDef"),
    dxb: get("dex-base"),
    dxc: get("dex-cur"),
    inb: get("ins-base"),
    inc: get("ins-cur"),
    mgb: get("mig-base"),
    mgc: get("mig-cur"),
    wpb: get("wlp-base"),
    wpc: get("wlp-cur"),
    hx: get("hpMax"),
    hc: get("hpCur"),
    mx: get("mpMax"),
    mc: get("mpCur"),
    ix: get("ipMax"),
    ic: get("ipCur"),
    fp: get("fpCount"),
    bp: get("backpack"),
    acn: get("acc-name"),
    acd: get("acc-desc"),
    amn: get("arm-name"),
    amd: get("arm-desc"),
    mhn: get("mh-name"),
    mhd: get("mh-desc"),
    ohn: get("oh-name"),
    ohd: get("oh-desc"),
    hs: get("heroicSkills"),
    rn: get("ritualsNotes"),
    sa,
    ma,
    da,
    bo: bonds.map((b) => ({ n: b.name, f: b.feelings })),
    pc: primaryClasses.map((c) => ({ n: c.name, b: c.benefits, s: c.skills })),
    oc: otherClasses.map((c) => ({ n: c.name, b: c.benefits, s: c.skills })),
    sp: spells.map((s) => ({
      n: s.name,
      nt: s.notes,
      mp: s.mp,
      tg: s.targets,
      dr: s.duration,
    })),
  };
}

function saveSheet(isAuto = false) {
  if (isAuto && urlMode) return;
  const data = collectData();
  localStorage.setItem("fabulaUltimaSheet", JSON.stringify(data));
  const st = document.getElementById("saveStatus");
  st.classList.add("show");
  setTimeout(() => st.classList.remove("show"), 2000);
}

function tryAutoLoad() {
  const raw = localStorage.getItem("fabulaUltimaSheet");
  if (raw)
    try {
      applyData(JSON.parse(raw));
    } catch (e) {}
}

function loadSheet() {
  const raw = localStorage.getItem("fabulaUltimaSheet");
  if (!raw) return alert("No saved sheet found.");
  try {
    applyData(JSON.parse(raw));
  } catch (e) {
    alert("Could not load sheet.");
  }
}

function applyData(d) {
  const set = (id, val) => {
    const el = document.getElementById(id);
    if (el && val !== undefined) el.value = val;
  };
  set("charName", d.n ?? d.name);
  set("charPronouns", d.pn ?? d.pronouns);
  set("charIdentity", d.id ?? d.identity);
  set("charTheme", d.th ?? d.theme);
  set("charOrigin", d.og ?? d.origin);
  set("charTraits", d.tr ?? d.traits);
  level = d.lv ?? d.level ?? 1;
  document.getElementById("levelDisplay").textContent = level;
  set("xpCurrent", d.xp);
  set("zenit", d.z ?? d.zenit);
  set("initMod", d.im ?? d.initMod);
  set("defense", d.df ?? d.defense);
  set("magDef", d.md ?? d.magDef);
  set("dex-base", d.dxb ?? d.dexBase);
  set("dex-cur", d.dxc ?? d.dexCur);
  set("ins-base", d.inb ?? d.insBase);
  set("ins-cur", d.inc ?? d.insCur);
  set("mig-base", d.mgb ?? d.migBase);
  set("mig-cur", d.mgc ?? d.migCur);
  set("wlp-base", d.wpb ?? d.wlpBase);
  set("wlp-cur", d.wpc ?? d.wlpCur);
  set("hpMax", d.hx ?? d.hpMax);
  set("hpCur", d.hc ?? d.hpCur);
  set("mpMax", d.mx ?? d.mpMax);
  set("mpCur", d.mc ?? d.mpCur);
  set("ipMax", d.ix ?? d.ipMax);
  set("ipCur", d.ic ?? d.ipCur);
  set("fpCount", d.fp);
  set("backpack", d.bp ?? d.backpack);
  set("acc-name", d.acn ?? d.accName);
  set("acc-desc", d.acd ?? d.accDesc);
  set("arm-name", d.amn ?? d.armName);
  set("arm-desc", d.amd ?? d.armDesc);
  set("mh-name", d.mhn ?? d.mhName);
  set("mh-desc", d.mhd ?? d.mhDesc);
  set("oh-name", d.ohn ?? d.ohName);
  set("oh-desc", d.ohd ?? d.ohDesc);
  set("heroicSkills", d.hs ?? d.heroicSkills);
  set("ritualsNotes", d.rn ?? d.ritualsNotes);

  // Statuses
  const sa = d.sa ?? d.statusesActive ?? [];
  document.querySelectorAll(".status-item").forEach((el) => {
    const active = sa.includes(el.dataset.status);
    el.classList.toggle("active-status", active);
    el.querySelector(".status-check").textContent = active ? "✗" : "";
  });

  // Martial
  const ma = d.ma ?? d.martialChecked ?? [];
  document.querySelectorAll(".martial-item").forEach((el) => {
    const checked = ma.includes(el.querySelector("span").textContent);
    el.classList.toggle("checked", checked);
    el.querySelector(".martial-box").textContent = checked ? "✓" : "";
  });

  // Disciplines
  const da = d.da ?? d.disciplinesChecked ?? [];
  document.querySelectorAll(".disc-item").forEach((el) => {
    const checked = da.includes(el.querySelector("span").textContent);
    el.classList.toggle("checked", checked);
    el.querySelector(".disc-box").textContent = checked ? "✓" : "";
  });

  const rawBonds = d.bo ?? d.bonds;
  if (rawBonds) {
    bonds = rawBonds.map((b) => ({
      name: b.n ?? b.name,
      feelings: b.f ?? b.feelings ?? [],
    }));
    renderBonds();
  }
  const rawPrimary = d.pc ?? d.primaryClasses;
  if (rawPrimary) {
    primaryClasses = rawPrimary.map((c) => ({
      name: c.n ?? c.name,
      benefits: c.b ?? c.benefits,
      skills: c.s ?? c.skills,
    }));
    renderPrimaryClasses();
  }
  const rawOther = d.oc ?? d.otherClasses;
  if (rawOther) {
    otherClasses = rawOther.map((c) => ({
      name: c.n ?? c.name,
      benefits: c.b ?? c.benefits,
      skills: c.s ?? c.skills,
    }));
    renderOtherClasses();
  }
  const rawSpells = d.sp ?? d.spells;
  if (rawSpells) {
    spells = rawSpells.map((s) => ({
      name: s.n ?? s.name,
      notes: s.nt ?? s.notes,
      mp: s.mp,
      targets: s.tg ?? s.targets,
      duration: s.dr ?? s.duration,
    }));
    renderSpells();
  }

  renderFP();
  updateXPBar();
  updateCrisis();
}

// ── EXPORT / IMPORT JSON ───────────────────────────
function exportSheet() {
  const data = collectData();
  const json = JSON.stringify(data, null, 2);
  const blob = new Blob([json], { type: "application/json" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  const charName =
    (data.n || "character").replace(/[^a-z0-9_\- ]/gi, "").trim() ||
    "character";
  a.href = url;
  a.download = charName + "-fabula-ultima.json";
  a.click();
  URL.revokeObjectURL(url);
}

function importSheet() {
  document.getElementById("importFileInput").value = "";
  document.getElementById("importFileInput").click();
}

function handleImportFile(input) {
  const file = input.files[0];
  if (!file) return;
  const reader = new FileReader();
  reader.onload = (e) => {
    try {
      const data = JSON.parse(e.target.result);
      applyData(data);
      saveSheet();
      const st = document.getElementById("saveStatus");
      st.textContent = "Imported!";
      st.classList.add("show");
      setTimeout(() => {
        st.classList.remove("show");
        st.textContent = "Saved!";
      }, 2500);
    } catch (err) {
      alert("Could not import: invalid JSON file.");
    }
  };
  reader.readAsText(file);
}

async function copyShareURL() {
  const json = JSON.stringify(collectData());
  const encoded = await compressToBase64(json);
  const url =
    window.location.origin +
    window.location.pathname +
    "?c=" +
    encodeURIComponent(encoded);
  await navigator.clipboard.writeText(url);
  const st = document.getElementById("copyStatus");
  st.classList.add("show");
  setTimeout(() => st.classList.remove("show"), 2000);
}

// ── THEME ──────────────────────────────────────────
function toggleTheme() {
  const html = document.documentElement;
  const goLight = html.dataset.theme !== "light";
  html.dataset.theme = goLight ? "light" : "dark";
  document.getElementById("themeToggle").textContent = goLight
    ? "☾ Dark"
    : "☀ Light";
  localStorage.setItem("fabulaUltimaTheme", html.dataset.theme);
}

// Auto-save every 30s
setInterval(() => saveSheet(true), 30000);

init();
