/* ============================================================
   auto-script.jsx — 自动主播剧本 + 用户评论注入
   按照游戏阶段节奏推进，每个决策点等待20秒收集评论
   ============================================================ */

(function() {
  if (!window.__AUTO_PLAY__) return;

  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
  let lastProcessedTimestamp = Date.now();

  const NARRATIVE_QUOTA_PER_WINDOW = 2;
  let narrativeCount = 0;

  function waitForReady() {
    return new Promise((resolve) => {
      const check = () => {
        if (window.__A) { resolve(); return; }
        setTimeout(check, 500);
      };
      check();
    });
  }

  // Click helper
  function forceClick(el) {
    if (!el) return false;
    el.click();
    el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
    return true;
  }

  // Find button by text content
  function findBtn(text) {
    const btns = document.querySelectorAll(".btn, button");
    for (const b of btns) {
      if (b.textContent.includes(text)) return b;
    }
    return null;
  }

  // Check if game is over
  function isGameOver() {
    return !!document.querySelector(".ending.fail, .ending.win, .settle");
  }

  // Block until no viewer-injected story is on screen
  async function holdWait() {
    while (window.__INJECT_HOLD_N > 0) await sleep(500);
  }

  // Dismiss any overlay (story/phase/decision/ending)
  function dismissOverlay() {
    // Game over — click "查看结算" then stop
    const ending = document.querySelector(".ending.fail, .ending.win");
    if (ending) {
      const settleBtn = ending.querySelector(".btn.ghost, button");
      if (settleBtn) {
        forceClick(settleBtn);
        console.log("[auto-script] Game over — clicked settle button");
        return true;
      }
    }
    // Story overlay
    const storyOverlay = document.querySelector(".story-overlay, .story-card");
    if (storyOverlay) {
      const btn = storyOverlay.querySelector("button, .btn");
      if (btn) { forceClick(btn); return true; }
    }
    // Phase overlay
    const phase = document.querySelector(".phase");
    if (phase) {
      const btn = phase.querySelector("button");
      if (btn) { forceClick(btn); return true; }
    }
    return false;
  }

  // Auto-pick first decision option
  function resolveDecision() {
    // Try multiple selectors — actual class is .opt .opt-btn
    const selectors = [".decision .opt .opt-btn", ".decision .opt-btn", ".dec-opt", ".d-opts .opt button"];
    for (const sel of selectors) {
      const opts = document.querySelectorAll(sel);
      if (opts.length > 0) {
        forceClick(opts[0]);
        console.log("[auto-script] Resolved decision via " + sel);
        return true;
      }
    }
    return false;
  }

  // Wait and keep dismissing overlays
  async function waitPhase(seconds, label) {
    console.log("[auto-script] Phase: " + label + " (" + seconds + "s)");
    const end = Date.now() + seconds * 1000;
    while (Date.now() < end) {
      if (window.__INJECT_HOLD_N > 0) { await sleep(500); continue; } // viewer story on screen — don't touch anything
      dismissOverlay();
      resolveDecision();
      await sleep(2000);
    }
  }

  // Poll for adopted comments
  async function pollAdoptedComments() {
    try {
      const res = await fetch("/api/comment");
      const data = await res.json();
      const comments = data.comments || [];
      const newAdopted = comments.filter(c =>
        c.adopted && c.timestamp > lastProcessedTimestamp
      );
      if (newAdopted.length > 0) {
        lastProcessedTimestamp = Math.max(...newAdopted.map(c => c.timestamp));
      }
      return newAdopted;
    } catch { return []; }
  }

  // Inject adopted comment into game
  // force=true: direct injection from the viewer page (bypasses per-window quota —
  // a real viewer's adopted comment must always land on screen)
  function injectIntoGame(comment, force) {
    const A = window.__A;
    if (!A) return;
    if (!force && narrativeCount >= NARRATIVE_QUOTA_PER_WINDOW) return;
    narrativeCount++;

    const user = comment.user;
    const narrative = comment.narrative || comment.text;

    // Hold the auto-play loop while a real viewer's story is on screen,
    // so scene transitions/decisions can't stomp it mid-typewriter.
    if (force) window.__INJECT_HOLD_N = (window.__INJECT_HOLD_N || 0) + 1;
    const releaseHold = () => {
      if (force) window.__INJECT_HOLD_N = Math.max(0, (window.__INJECT_HOLD_N || 1) - 1);
    };

    if (A.showBanner) {
      A.showBanner({ icon: "✨", big: true, html: "<b>@" + user + "</b>" + t(" 的创意改变了游戏世界！", "'s idea just reshaped the game world!") });
    }
    if (A.setStory) {
      // Typewriter runs at 45ms/char — keep the card up until it finishes + reading time
      const showMs = Math.max(6000, (narrative || "").length * 45 + 3000);
      const storyObj = { illus: "✨", text: narrative, source: "@" + user, onContinue: () => A.setStory(null) };
      setTimeout(() => {
        A.setStory(storyObj);
        // Only dismiss if OUR story is still up — a newer injected story must not be cut short
        setTimeout(() => { A.setStory((cur) => (cur === storyObj ? null : cur)); releaseHold(); }, showMs);
      }, 1200);
    } else {
      releaseHold();
    }
    // Apply stat changes from AI
    const stats = comment.stats;
    if (A.applyStats && stats) {
      setTimeout(() => {
        const delta = {};
        if (stats.hp) delta.hp = stats.hp;
        if (stats.hunger) delta.hunger = stats.hunger;
        if (stats.sanity) delta.sanity = stats.sanity;
        if (stats.supply) delta.supply = stats.supply;
        if (Object.keys(delta).length > 0) {
          A.applyStats(delta);
          // Show toast with stat changes
          const parts = [];
          if (delta.hp) parts.push("HP " + (delta.hp > 0 ? "+" : "") + delta.hp);
          if (delta.hunger) parts.push(t("饱腹 ", "Food ") + (delta.hunger > 0 ? "+" : "") + delta.hunger);
          if (delta.sanity) parts.push(t("理智 ", "Sanity ") + (delta.sanity > 0 ? "+" : "") + delta.sanity);
          if (delta.supply) parts.push(t("物资 ", "Supplies ") + (delta.supply > 0 ? "+" : "") + delta.supply);
          if (A.toast && parts.length > 0) {
            A.toast({ icon: "📊", name: parts.join(" · ") });
          }
        }
      }, 5000);
    }
  }

  // Direct injection channel: the parent viewer page (mobile) posts adopted
  // comments here after /api/comment responds — more reliable than polling
  // the server buffer (which is per-instance memory on serverless).
  window.addEventListener("message", (e) => {
    const d = e && e.data;
    if (!d || d.type !== "wl_adopted") return;
    lastProcessedTimestamp = Date.now(); // poll loop must not re-inject this one
    const c = { user: d.user, text: d.text, narrative: d.narrative, stats: d.stats };
    const tryInject = (attempts) => {
      if (window.__A) { injectIntoGame(c, true); return; }
      if (attempts > 0) setTimeout(() => tryInject(attempts - 1), 1500);
    };
    tryInject(8);
  });

  // Poll loop — runs in background, also clears stuck overlays/decisions
  async function pollLoop() {
    while (true) {
      await sleep(3000);
      if (window.__INJECT_HOLD_N > 0) continue; // viewer story on screen — hands off

      // Always try to dismiss stuck overlays/decisions
      const decOpts = document.querySelectorAll(".decision .opt .opt-btn, .decision .opt-btn");
      if (decOpts.length > 0) {
        // Decision has been showing — wait 8 seconds then auto-resolve
        await sleep(8000);
        const stillThere = document.querySelectorAll(".decision .opt .opt-btn, .decision .opt-btn");
        if (stillThere.length > 0) {
          forceClick(stillThere[0]);
          console.log("[auto-script] Poll loop auto-resolved stuck decision");
        }
      }

      dismissOverlay();

      const adopted = await pollAdoptedComments();
      for (const comment of adopted) {
        injectIntoGame(comment);
        await sleep(3000);
      }
    }
  }

  // ============================================================
  // MAIN GAME LOOP — follows the 6-phase daily cycle
  // ============================================================
  async function runDay(dayNum) {
    if (isGameOver()) { console.log("[auto-script] Game over, stopping"); return false; }
    console.log("[auto-script] ===== DAY " + dayNum + " =====");
    narrativeCount = 0;

    // Phase 1: Home — observe the scene (15s)
    await waitPhase(15, "家中 · 观察");

    // Phase 2: Organize — wait for user comments about what to bring (20s)
    await waitPhase(20, "整理资源 · 收集评论");

    // Phase 3: Go out — click the go out button
    await holdWait();
    const goOutBtn = findBtn(t("准备出门", "Head Out"));
    if (goOutBtn) {
      forceClick(goOutBtn);
      console.log("[auto-script] Clicked 准备出门");
    }
    await sleep(3000);
    dismissOverlay(); // dismiss phase transition
    await sleep(2000);

    // Phase 4: Choose destination (20s for user comments)
    await waitPhase(10, "选择目的地 · 收集评论");
    await holdWait();
    const destCard = document.querySelector(".dest-card");
    if (destCard) {
      forceClick(destCard);
      console.log("[auto-script] Selected destination");
      await sleep(1500);
      // Confirm
      const confirmBtn = findBtn(t("出发", "Go")) || findBtn(t("确认", "Confirm")) || findBtn(t("前往", "Head to"));
      if (confirmBtn) forceClick(confirmBtn);
    }
    await sleep(3000);
    dismissOverlay();
    await sleep(2000);
    narrativeCount = 0;

    // Phase 5: Explore — walk 4 tiles, each with collection window
    for (let tile = 0; tile < 5; tile++) {
      if (isGameOver()) return false;
      // Wait for user comments (15s per tile)
      await waitPhase(10, "探索格子 " + (tile + 1));
      await holdWait();

      // Click adjacent hex
      const hex = document.querySelector(".hex.adjacent");
      if (hex) {
        forceClick(hex);
        console.log("[auto-script] Walked to hex tile " + (tile + 1));
        narrativeCount = 0;
      } else {
        console.log("[auto-script] No adjacent hex found, checking for return");
        break;
      }

      await sleep(3000);

      // Keep dismissing overlays and resolving decisions until clear
      for (let i = 0; i < 5; i++) {
        await holdWait();
        if (dismissOverlay() || resolveDecision()) {
          await sleep(3000);
        } else {
          break;
        }
      }
      await sleep(2000);
    }

    // Phase 6: Return home
    await sleep(3000);
    await holdWait();
    const returnBtn = findBtn(t("返回避难所", "return to shelter"));
    if (returnBtn) {
      forceClick(returnBtn);
      console.log("[auto-script] Returning home");
    }
    await sleep(3000);
    dismissOverlay();
    await sleep(3000);
    dismissOverlay();
  }

  async function main() {
    await waitForReady();
    console.log("[auto-script] Game ready — starting 7-day loop");

    // Initial wait — let user see home scene
    await sleep(8000);

    for (let day = 1; day <= 7; day++) {
      const ok = await runDay(day);
      if (ok === false) break;  // game over
      if (isGameOver()) { dismissOverlay(); break; }
      // Brief pause between days
      await sleep(5000);
      dismissOverlay();
      await sleep(2000);
    }

    console.log("[auto-script] 7 days complete");
  }

  // Start both loops
  waitForReady().then(() => {
    pollLoop();
    main();
  });
})();
