/* =========================================================
   gg_lyra.js — CANONICAL LYRA STORM SYSTEM
   Purpose:
   - plugs into canonical gg_save only
   - works with canonical gg_weather.js
   - Lyra contracts / favor / skills / Tempest raid progress
   - emits canonical gg:* events only
   ========================================================= */
(() => {
  "use strict";

  const GG = (window.GG = window.GG || {});
  const API = (GG.LYRA = GG.LYRA || {});
  const KEY = "gg_save";
  const SOURCE = "gg_lyra";

  if (API.__installed) return;
  API.__installed = true;

  const CONTRACTS = [
    {
      id: "fog_cover",
      name: "Fog Cover",
      cost: 5000,
      weather: "FOG",
      district: "Null Quarter",
      durationMinutes: 20,
      favorGain: 2,
      desc: "Lyra blankets the district in fog. Stealth and sabotage become easier."
    },
    {
      id: "lightning_chaos",
      name: "Lightning Chaos",
      cost: 7500,
      weather: "STORM",
      district: "Null Quarter",
      durationMinutes: 20,
      favorGain: 3,
      desc: "A violent electrical storm empowers Soultech and raid damage."
    },
    {
      id: "grid_blackout",
      name: "Grid Blackout",
      cost: 10000,
      weather: "BLACKOUT",
      district: "Null Quarter",
      durationMinutes: 20,
      favorGain: 4,
      desc: "Lyra crushes the district power grid. Hacking and stealth spike upward."
    },
    {
      id: "rain_screen",
      name: "Rain Screen",
      cost: 4000,
      weather: "RAIN",
      district: "Ashen Heights",
      durationMinutes: 15,
      favorGain: 1,
      desc: "A rain front lowers visibility and helps quiet movement."
    },
    {
      id: "lyra_storm",
      name: "Lyra Storm",
      cost: 15000,
      weather: "LYRA_STORM",
      district: "Null Quarter",
      durationMinutes: 20,
      favorGain: 5,
      desc: "Lyra unleashes her signature Null-laced superstorm across the district."
    }
  ];

  const SKILLS = [
    { id: "static_charge", tier: 1, favorReq: 3,  name: "Static Charge", desc: "+10% electricity damage." },
    { id: "storm_sense", tier: 1, favorReq: 3,  name: "Storm Sense", desc: "See movement through fog and rain." },
    { id: "lightning_dash", tier: 2, favorReq: 6,  name: "Lightning Dash", desc: "Short warp dash with electric trail." },
    { id: "cloud_cover", tier: 2, favorReq: 6,  name: "Cloud Cover", desc: "Reduces enemy accuracy during combat." },
    { id: "thunder_strike", tier: 3, favorReq: 9,  name: "Thunder Strike", desc: "Call down a devastating lightning hit." },
    { id: "blackout_field", tier: 3, favorReq: 9,  name: "Blackout Field", desc: "Crush nearby HUD and signal systems." },
    { id: "tempest_dominion", tier: 4, favorReq: 12, name: "Tempest Dominion", desc: "Control district weather itself." }
  ];

  function rawGet() {
    try {
      return JSON.parse(localStorage.getItem(KEY) || "{}");
    } catch (e) {
      return {};
    }
  }

  function rawSet(v) {
    try {
      localStorage.setItem(KEY, JSON.stringify(v || {}));
    } catch (e) {}
  }

  function getSave() {
    try {
      if (typeof GG.getSave === "function") return GG.getSave() || {};
    } catch (e) {}
    return rawGet();
  }

  function setSave(v, source = SOURCE) {
    try {
      if (typeof GG.setSave === "function") {
        GG.setSave(v || {}, source);
        return v || {};
      }
    } catch (e) {}

    rawSet(v || {});
    emit("save-updated", { source, save: v || {} });
    return v || {};
  }

  function emit(name, detail) {
    try {
      if (typeof GG.emit === "function") GG.emit(name, detail);
    } catch (e) {}
    try {
      window.dispatchEvent(new CustomEvent("gg:" + name, { detail: detail || {} }));
    } catch (e) {}
  }

  function num(v, d = 0) {
    return (typeof v === "number" && !isNaN(v)) ? v : d;
  }

  function clone(v) {
    try {
      return JSON.parse(JSON.stringify(v || {}));
    } catch (e) {
      return {};
    }
  }

  function esc(str) {
    return String(str ?? "").replace(/[&<>"']/g, function (m) {
      return {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#039;"
      }[m];
    });
  }

  function syncMoney(s) {
    const g = num(
      typeof s.gold === "number" ? s.gold :
      (typeof s.gg === "number" ? s.gg :
      (typeof s.cash === "number" ? s.cash : 0)),
      0
    );

    s.gold = g;
    s.gg = g;
    s.cash = g;
  }

  function ensure() {
    const s = getSave() || {};
    let changed = false;

    syncMoney(s);

    if (!s.lyra || typeof s.lyra !== "object") {
      s.lyra = {};
      changed = true;
    }

    if (typeof s.lyra.unlocked !== "boolean") {
      s.lyra.unlocked = true;
      changed = true;
    }
    if (typeof s.lyra.favor !== "number") {
      s.lyra.favor = 0;
      changed = true;
    }
    if (typeof s.lyra.contractsBought !== "number") {
      s.lyra.contractsBought = 0;
      changed = true;
    }
    if (typeof s.lyra.bossClears !== "number") {
      s.lyra.bossClears = 0;
      changed = true;
    }
    if (typeof s.lyra.lastStormAt !== "number") {
      s.lyra.lastStormAt = 0;
      changed = true;
    }
    if (!Array.isArray(s.lyra.skills)) {
      s.lyra.skills = [];
      changed = true;
    }
    if (!Array.isArray(s.lyra.logs)) {
      s.lyra.logs = [];
      changed = true;
    }

    if (!s.tempestRaid || typeof s.tempestRaid !== "object") {
      s.tempestRaid = {};
      changed = true;
    }

    if (typeof s.tempestRaid.unlocked !== "boolean") {
      s.tempestRaid.unlocked = true;
      changed = true;
    }
    if (typeof s.tempestRaid.bestPhase !== "number") {
      s.tempestRaid.bestPhase = 0;
      changed = true;
    }
    if (typeof s.tempestRaid.clears !== "number") {
      s.tempestRaid.clears = 0;
      changed = true;
    }
    if (!Array.isArray(s.tempestRaid.history)) {
      s.tempestRaid.history = [];
      changed = true;
    }

    if (changed) setSave(s, "gg_lyra_ensure");
    return s;
  }

  function addLog(s, text, type = "info") {
    s.lyra.logs.unshift({
      text: String(text || ""),
      type: String(type || "info"),
      at: Date.now()
    });
    s.lyra.logs = s.lyra.logs.slice(0, 25);
  }

  function getContracts() {
    return CONTRACTS.slice();
  }

  function getSkills() {
    return SKILLS.slice();
  }

  function getContractById(contractId) {
    return CONTRACTS.find(c => c.id === contractId) || null;
  }

  function getSkillById(skillId) {
    return SKILLS.find(x => x.id === skillId) || null;
  }

  function getStatus() {
    const s = ensure();

    return {
      unlocked: !!s.lyra.unlocked,
      favor: num(s.lyra.favor, 0),
      contractsBought: num(s.lyra.contractsBought, 0),
      bossClears: num(s.lyra.bossClears, 0),
      lastStormAt: num(s.lyra.lastStormAt, 0),
      skills: clone(s.lyra.skills || []),
      logs: clone(s.lyra.logs || []),
      weather: (GG.WEATHER && typeof GG.WEATHER.getWeatherState === "function")
        ? GG.WEATHER.getWeatherState()
        : null,
      tempestRaid: clone(s.tempestRaid || {})
    };
  }

  function buyContract(contractId) {
    const s = ensure();
    const contract = getContractById(contractId);

    if (!contract) {
      return { ok: false, msg: "Unknown Lyra contract." };
    }

    if (!s.lyra.unlocked) {
      return { ok: false, msg: "Lyra not unlocked." };
    }

    syncMoney(s);

    if (num(s.gold, 0) < num(contract.cost, 0)) {
      return { ok: false, msg: "Not enough gold for this contract." };
    }

    if (!GG.WEATHER || typeof GG.WEATHER.setWeather !== "function") {
      return { ok: false, msg: "Weather system missing." };
    }

    s.gold -= num(contract.cost, 0);
    syncMoney(s);

    s.lyra.contractsBought += 1;
    s.lyra.favor += num(contract.favorGain, 0);

    const weatherDef = GG.WEATHER.setWeather(
      contract.weather,
      contract.district,
      contract.durationMinutes,
      "lyra_contract"
    );

    if (String(contract.weather).toUpperCase() === "LYRA_STORM") {
      s.lyra.lastStormAt = Date.now();
    }

    addLog(
      s,
      `Bought ${contract.name} for ${contract.cost.toLocaleString()} gold.`,
      "contract"
    );

    setSave(s, "gg_lyra_buy_contract");

    emit("lyra", {
      action: "buy_contract",
      contract: clone(contract),
      weather: clone(weatherDef),
      favor: s.lyra.favor
    });

    return {
      ok: true,
      msg: `${contract.name} activated.`,
      contract: clone(contract),
      weather: clone(weatherDef),
      favor: s.lyra.favor,
      gold: s.gold
    };
  }

  function unlockSkill(skillId) {
    const s = ensure();
    const skill = getSkillById(skillId);

    if (!skill) return { ok: false, msg: "Unknown Tempest skill." };
    if (!s.lyra.unlocked) return { ok: false, msg: "Lyra not unlocked." };
    if (s.lyra.skills.includes(skillId)) return { ok: false, msg: "Skill already unlocked." };

    const requiredFavor = num(skill.favorReq, skill.tier * 3);
    if (num(s.lyra.favor, 0) < requiredFavor) {
      return { ok: false, msg: `Need ${requiredFavor} Lyra favor.` };
    }

    s.lyra.skills.push(skillId);
    addLog(s, `Unlocked skill: ${skill.name}.`, "skill");
    setSave(s, "gg_lyra_unlock_skill");

    emit("lyra", {
      action: "unlock_skill",
      skill: clone(skill),
      favor: s.lyra.favor
    });

    return {
      ok: true,
      msg: `${skill.name} unlocked.`,
      skill: clone(skill),
      favor: s.lyra.favor
    };
  }

  function clearBossPhase(phase) {
    const s = ensure();
    const p = Math.max(1, Math.floor(Number(phase || 1)));

    s.tempestRaid.bestPhase = Math.max(num(s.tempestRaid.bestPhase, 0), p);

    let favorGain = 1;
    if (p >= 4) {
      favorGain = 5;
      s.tempestRaid.clears += 1;
      s.lyra.bossClears += 1;
      addLog(s, "Defeated Lyra Storm — Tempest Unbound.", "raid");
    } else {
      addLog(s, `Reached Tempest raid phase ${p}.`, "raid");
    }

    s.lyra.favor += favorGain;

    s.tempestRaid.history.unshift({
      at: Date.now(),
      phase: p,
      clear: p >= 4,
      favorGain
    });
    s.tempestRaid.history = s.tempestRaid.history.slice(0, 20);

    setSave(s, "gg_lyra_boss_phase");

    emit("lyra", {
      action: "raid_progress",
      phase: p,
      favorGain,
      bestPhase: s.tempestRaid.bestPhase,
      clears: s.tempestRaid.clears
    });

    return {
      ok: true,
      msg: p >= 4 ? "Raid clear recorded." : `Raid phase ${p} recorded.`,
      phase: p,
      favorGain,
      bestPhase: s.tempestRaid.bestPhase,
      clears: s.tempestRaid.clears
    };
  }

  function ensureStyle() {
    if (document.getElementById("ggLyraStyle")) return;

    const st = document.createElement("style");
    st.id = "ggLyraStyle";
    st.textContent = `
      .lyraGrid{
        display:grid;
        grid-template-columns:1fr 1fr;
        gap:16px;
      }
      .lyraPanel{
        border:1px solid rgba(255,255,255,.10);
        background:rgba(10,14,28,.82);
        border-radius:22px;
        padding:16px;
        box-shadow:0 20px 60px rgba(0,0,0,.32);
      }
      .lyraPanel h3{
        margin:0 0 12px;
        font-size:20px;
        color:#eef2ff;
      }
      .lyraCard{
        border:1px solid rgba(255,255,255,.08);
        background:rgba(255,255,255,.04);
        border-radius:16px;
        padding:14px;
        margin-bottom:10px;
      }
      .lyraTop{
        display:flex;
        align-items:flex-start;
        justify-content:space-between;
        gap:10px;
      }
      .lyraName{
        color:#eef2ff;
        font-size:16px;
        font-weight:1000;
      }
      .lyraCost{
        margin-top:4px;
        color:#7df1df;
        font-size:12px;
        font-weight:900;
        text-transform:uppercase;
        letter-spacing:.12em;
      }
      .lyraDesc{
        margin-top:8px;
        color:rgba(238,242,255,.76);
        line-height:1.5;
        font-size:13px;
      }
      .lyraBtn{
        border:1px solid rgba(115,168,255,.30);
        background:linear-gradient(135deg,rgba(115,168,255,.16),rgba(125,241,223,.10));
        color:#eef2ff;
        border-radius:12px;
        padding:10px 12px;
        font-weight:900;
        cursor:pointer;
      }
      .lyraBtn.isOff{
        opacity:.6;
        cursor:not-allowed;
      }
      .lyraProfile{
        border:1px solid rgba(255,255,255,.10);
        background:rgba(10,14,28,.82);
        border-radius:22px;
        padding:16px;
        box-shadow:0 20px 60px rgba(0,0,0,.32);
      }
      .lyraProfileName{
        font-size:22px;
        font-weight:1000;
        color:#eef2ff;
      }
      .lyraProfileSub{
        margin-top:6px;
        color:rgba(238,242,255,.72);
        font-size:13px;
      }
      .lyraTags{
        display:flex;
        flex-wrap:wrap;
        gap:8px;
        margin-top:12px;
      }
      .lyraTags span{
        padding:8px 10px;
        border-radius:999px;
        border:1px solid rgba(255,255,255,.08);
        background:rgba(255,255,255,.04);
        color:#eef2ff;
        font-size:12px;
        font-weight:900;
      }
      .lyraRaidWrap{
        border:1px solid rgba(255,255,255,.10);
        background:rgba(10,14,28,.82);
        border-radius:22px;
        padding:16px;
        box-shadow:0 20px 60px rgba(0,0,0,.32);
      }
      .lyraRaidTitle{
        color:#eef2ff;
        font-weight:1000;
        font-size:18px;
      }
      .lyraRaidButtons{
        display:flex;
        flex-wrap:wrap;
        gap:8px;
        margin-top:12px;
      }
      .lyraLog{
        border-bottom:1px solid rgba(255,255,255,.06);
        padding:8px 0;
        color:rgba(238,242,255,.78);
        font-size:13px;
      }
      @media (max-width:860px){
        .lyraGrid{ grid-template-columns:1fr; }
      }
    `;
    document.head.appendChild(st);
  }

  function renderContracts(target) {
    const host = typeof target === "string" ? document.querySelector(target) : target;
    if (!host) return;

    const s = ensure();

    host.innerHTML = CONTRACTS.map(c => `
      <div class="lyraCard">
        <div class="lyraTop">
          <div>
            <div class="lyraName">${esc(c.name)}</div>
            <div class="lyraCost">${Number(c.cost).toLocaleString()} gold • +${Number(c.favorGain || 0)} favor</div>
          </div>
          <button class="lyraBtn" data-lyra-buy="${esc(c.id)}" type="button">Buy</button>
        </div>
        <div class="lyraDesc">${esc(c.desc)}</div>
        <div class="lyraDesc">Weather: ${esc(c.weather)} • District: ${esc(c.district)} • ${Number(c.durationMinutes)} min</div>
        <div class="lyraDesc">Wallet: ${num(s.gold, 0).toLocaleString()} gold</div>
      </div>
    `).join("");

    host.querySelectorAll("[data-lyra-buy]").forEach(btn => {
      btn.addEventListener("click", () => {
        const out = buyContract(btn.getAttribute("data-lyra-buy"));
        alert(out.msg);
        renderContracts(target);
        renderProfile("#lyraProfileMount");
        renderLogs("#lyraLogMount");
      });
    });
  }

  function renderSkills(target) {
    const host = typeof target === "string" ? document.querySelector(target) : target;
    if (!host) return;

    const s = ensure();

    host.innerHTML = SKILLS.map(skill => {
      const unlocked = s.lyra.skills.includes(skill.id);
      const need = num(skill.favorReq, skill.tier * 3);

      return `
        <div class="lyraCard">
          <div class="lyraTop">
            <div>
              <div class="lyraName">T${skill.tier} • ${esc(skill.name)}</div>
              <div class="lyraCost">${unlocked ? "Unlocked" : `Need ${need} favor`}</div>
            </div>
            <button class="lyraBtn ${unlocked ? "isOff" : ""}" data-lyra-skill="${esc(skill.id)}" type="button" ${unlocked ? "disabled" : ""}>
              ${unlocked ? "Owned" : "Unlock"}
            </button>
          </div>
          <div class="lyraDesc">${esc(skill.desc)}</div>
        </div>
      `;
    }).join("");

    host.querySelectorAll("[data-lyra-skill]").forEach(btn => {
      btn.addEventListener("click", () => {
        const out = unlockSkill(btn.getAttribute("data-lyra-skill"));
        alert(out.msg);
        renderSkills(target);
        renderProfile("#lyraProfileMount");
        renderLogs("#lyraLogMount");
      });
    });
  }

  function renderProfile(target) {
    const host = typeof target === "string" ? document.querySelector(target) : target;
    if (!host) return;

    const s = ensure();
    const weatherState = (GG.WEATHER && typeof GG.WEATHER.getWeatherState === "function")
      ? GG.WEATHER.getWeatherState()
      : null;

    host.innerHTML = `
      <div class="lyraProfile">
        <div class="lyraProfileName">Lyra Storm — The Tempest Broker</div>
        <div class="lyraProfileSub">Null Quarter • Weather-Tech Operator • Stormgrid Tower</div>
        <div class="lyraTags">
          <span>Favor ${num(s.lyra.favor, 0)}</span>
          <span>Contracts ${num(s.lyra.contractsBought, 0)}</span>
          <span>Boss Clears ${num(s.lyra.bossClears, 0)}</span>
          <span>Skills ${Array.isArray(s.lyra.skills) ? s.lyra.skills.length : 0}</span>
          <span>Weather ${esc(weatherState && weatherState.current ? weatherState.current.name : "Unknown")}</span>
        </div>
      </div>
    `;
  }

  function renderRaid(target) {
    const host = typeof target === "string" ? document.querySelector(target) : target;
    if (!host) return;

    const s = ensure();

    host.innerHTML = `
      <div class="lyraRaidWrap">
        <div class="lyraRaidTitle">Tempest Unbound Raid</div>
        <div class="lyraDesc">Fight Lyra atop the Stormgrid Tower through rain, lightning, blackout, and final tempest surge.</div>
        <div class="lyraTags">
          <span>Best Phase ${num(s.tempestRaid.bestPhase, 0)}</span>
          <span>Total Clears ${num(s.tempestRaid.clears, 0)}</span>
        </div>
        <div class="lyraRaidButtons">
          <button class="lyraBtn" data-phase="1" type="button">Phase 1</button>
          <button class="lyraBtn" data-phase="2" type="button">Phase 2</button>
          <button class="lyraBtn" data-phase="3" type="button">Phase 3</button>
          <button class="lyraBtn" data-phase="4" type="button">Clear Raid</button>
        </div>
      </div>
    `;

    host.querySelectorAll("[data-phase]").forEach(btn => {
      btn.addEventListener("click", () => {
        const out = clearBossPhase(btn.getAttribute("data-phase"));
        alert(out.msg);
        renderRaid(target);
        renderProfile("#lyraProfileMount");
        renderLogs("#lyraLogMount");
      });
    });
  }

  function renderLogs(target) {
    const host = typeof target === "string" ? document.querySelector(target) : target;
    if (!host) return;

    const s = ensure();
    const logs = Array.isArray(s.lyra.logs) ? s.lyra.logs : [];

    host.innerHTML = logs.map(log => `
      <div class="lyraLog">${esc(log.text)}</div>
    `).join("") || `<div class="lyraLog">No Lyra activity yet.</div>`;
  }

  function autoRefreshMounts() {
    if (document.querySelector("#lyraProfileMount")) renderProfile("#lyraProfileMount");
    if (document.querySelector("#lyraContractsMount")) renderContracts("#lyraContractsMount");
    if (document.querySelector("#lyraSkillsMount")) renderSkills("#lyraSkillsMount");
    if (document.querySelector("#lyraRaidMount")) renderRaid("#lyraRaidMount");
    if (document.querySelector("#lyraLogMount")) renderLogs("#lyraLogMount");
  }

  ensureStyle();
  ensure();

  API.ensure = ensure;
  API.getContracts = getContracts;
  API.getSkills = getSkills;
  API.getStatus = getStatus;
  API.buyContract = buyContract;
  API.unlockSkill = unlockSkill;
  API.clearBossPhase = clearBossPhase;
  API.renderContracts = renderContracts;
  API.renderSkills = renderSkills;
  API.renderProfile = renderProfile;
  API.renderRaid = renderRaid;
  API.renderLogs = renderLogs;
  API.autoRefresh = autoRefreshMounts;

  window.addEventListener("gg:weather-updated", autoRefreshMounts);
  window.addEventListener("gg:save-updated", function (e) {
    const src = e && e.detail && e.detail.source;
    if (src === SOURCE) return;
    autoRefreshMounts();
  });
})();