/* ============================================================
   mobile-app.jsx — 观众手机端 4-page prototype
   pages: cover → identity → room (portrait) ⇄ fullscreen (landscape)
   ============================================================ */
const { useState: useS, useEffect: useE, useRef: useR, useLayoutEffect: useL } = React;

let _mid = 0;
const mid = () => "m" + (++_mid);
const pick = (a) => a[Math.floor(Math.random() * a.length)];

const AVATARS = ["🦊", "🐱", "🪖", "🤖", "🌙", "👻", "🥷", "🦉"];
const SCENE_KEYS = ["home", "hospital", "factory", "subway", "market"];

/* ---- the 16:9 live game feed (iframe embedding host game view) ---- */
function GameFeed({ landscape }) {
  return (
    <div className="feed-inner" style={{ position: "absolute", inset: 0 }}>
      <iframe
        src="/wasteland/game-feed.html"
        style={{
          width: "100%",
          height: "100%",
          border: "none",
          background: "#000",
        }}
        allow="autoplay"
        sandbox="allow-scripts allow-same-origin"
      />
    </div>
  );
}

/* ---- unified sync bubble (creative adopted notification) ---- */
function SyncBubble({ type, user, name }) {
  const map = { event: [t("剧情", "story"), "event"], character: [t("角色", "character"), "character"], item: [t("道具", "item"), "item"], location: [t("地点", "location"), "location"] };
  const [lbl, cls] = map[type] || [t("剧情", "story"), "event"];
  return (
    <div className="sync-bubble">
      <span className="sb-spark">✨ </span><span className="sb-user">{user}</span>
      <span className="sb-verb">{t(" 的创意生效了 · ", "'s idea went live · ")}</span>
      <span className={"sb-type " + cls}>{lbl}</span>
      <span className="sb-name">{t("「", "“")}{name}{t("」", "”")}</span>
    </div>
  );
}

/* ---- comment waterfall overlay ---- */
function CommentWaterfall({ comments, variant, storyActive }) {
  const endRef = React.useRef(null);
  React.useEffect(() => {
    if (endRef.current) endRef.current.scrollIntoView({ behavior: "smooth" });
  }, [comments]);
  return (
    <div className={"cmt-overlay " + (variant || "") + (storyActive ? " story-active" : "")}>
      {comments.map((c) => (
        c.sync ? <SyncBubble key={c.id} type={c.sync.type} user={c.sync.user} name={c.sync.name} /> :
        <div key={c.id} className={"m-cmt " + (c.mine ? "mine " : "") + (c.adopted ? "adopted " : "") + (c.sys ? "sys " : "")}>
          {c.sys ? <span className="t">{c.text}</span> : (
            <React.Fragment>
              <span className="u">{c.user}</span><span className="t">{window.t("：", ": ")}{c.text}</span>
              {c.adopted && <span className="adopt">✓ {window.t("已融入游戏世界", "Now part of the game world")}</span>}
            </React.Fragment>
          )}
        </div>
      ))}
      <div ref={endRef} />
    </div>
  );
}


function MobileApp() {
  const [page, setPage] = useS("cover");        // cover | identity | room
  const [fs, setFs] = useS(false);              // landscape fullscreen
  const [nick, setNick] = useS("");
  const [avatar, setAvatar] = useS("🦊");
  const [comments, setComments] = useS([]);
  const [likes, setLikes] = useS(12483);
  const [viewers, setViewers] = useS(1243);
  const [quota, setQuota] = useS(5);
  const [val, setVal] = useS("");
  const [kbUp, setKbUp] = useS(false);
  const [sceneKey, setSceneKey] = useS("home");
  const [showRotate, setShowRotate] = useS(false);
  const [dayPip] = useS(1);
  const [countdown, setCountdown] = useS(20);
  const [cdPhase, setCdPhase] = useS("collect"); // "collect" | "decide"
  const [storyActive, setStoryActive] = useS(false);

  const deviceRef = useR(null);
  const inputRef = useR(null);
  const sceneIdx = useR(0);
  const sendCount = useR(0);

  /* device scaling + rotation */
  useL(() => {
    const fit = () => {
      if (!deviceRef.current) return;
      const W = fs ? 812 : 375, H = fs ? 375 : 812;
      const sc = Math.min(window.innerWidth / W, window.innerHeight / H) * 0.96;
      deviceRef.current.style.transform = "scale(" + sc + ")";
    };
    fit();
    window.addEventListener("resize", fit);
    return () => window.removeEventListener("resize", fit);
  }, [fs]);

  const pushCmt = (c, opts = {}) => {
    const id = mid();
    setComments((cs) => [...cs.slice(-30), { ...c, id, ...opts }]);
    return id;
  };

  /* Countdown timer: 20s collect → 10s decide → repeat */
  useE(() => {
    if (page !== "room") return;
    const tick = setInterval(() => {
      setCountdown((c) => {
        if (c <= 1) {
          setCdPhase((p) => {
            const next = p === "collect" ? "decide" : "collect";
            setCountdown(next === "collect" ? 20 : 10);
            return next;
          });
          return 0;
        }
        return c - 1;
      });
    }, 1000);
    return () => clearInterval(tick);
  }, [page]);

  /* Poll backend for comments + ambient simulation */
  useE(() => {
    if (page !== "room") return;

    // Ambient comments to simulate activity
    const ambientTimer = setInterval(() => {
      pushCmt(pick(window.AMBIENT_COMMENTS));
      setViewers((v) => v + Math.floor(Math.random() * 7) - 2);
      setLikes((l) => l + Math.floor(Math.random() * 12));
    }, 2800);

    // Occasional "comment adopted" — unified sync bubble
    const SYNC_TYPES = ["event", "character", "item", "location"];
    const SYNC_NAMES = [t("有人在敲门", "Someone's Knocking"), t("拾荒者老鸦", "Crow the Scavenger"), t("改装手枪", "Modded Pistol"), t("废弃医院", "Abandoned Hospital"), t("毒雾扩散", "Toxic Fog Spreads"), t("机械狗Rusty", "Rusty the Robo-Dog"), t("信号枪", "Flare Gun"), t("地下停车场", "Underground Garage")];
    const adoptTimer = setInterval(() => {
      const who = pick(window.AMBIENT_COMMENTS);
      pushCmt({}, { sync: { type: pick(SYNC_TYPES), user: "@" + who.user, name: pick(SYNC_NAMES) } });
    }, 15000);

    return () => { clearInterval(ambientTimer); clearInterval(adoptTimer); };
  }, [page]);

  const enterRoom = () => { setNick(nick.trim() || t("幸存者", "Survivor")); setComments([]); setPage("room"); };

  /* Offline fallback: rule-based classification + template narrative.
     Guarantees the comment→story loop still works when /api/comment is
     unreachable (static deploy, missing API key, network hiccup). */
  const localClassify = (text) => {
    const zero = { hp: 0, hunger: 0, sanity: 0, supply: 0 };
    const noise = /^([0-9]+|6+|哈+|h+a+h*a*|l+o+l+|w+|f+|g+|[^\w一-龥]+)$/i;
    if (noise.test(text) || text.trim().length < 3) {
      return { adopted: false, classification: "IRRELEVANT", narrative: t("评论已记录", "Comment logged"), stats: zero };
    }
    const rules = [
      { re: /(枪|剑|刀|药|食物|钥匙|罐头|电池|手电|gun|sword|knife|med|pill|food|key|can|battery|flashlight|weapon|radio)/i, cls: "ITEM" },
      { re: /(医院|超市|工厂|地铁|商场|公园|隧道|hospital|market|store|factory|subway|mall|park|tunnel|bunker|tower)/i, cls: "LOCATION" },
      { re: /(幸存者|士兵|医生|老人|商人|女孩|男孩|机器人|survivor|soldier|doctor|stranger|merchant|girl|boy|dog|cat|robot|trader)/i, cls: "CHARACTER" },
      { re: /(暴风|丧尸|空投|地震|着火|袭击|出现|遇到|storm|zombie|airdrop|earthquake|fire|attack|appears?|ambush|horde|siren)/i, cls: "EVENT" },
    ];
    const hit = rules.find((r) => r.re.test(text));
    const cls = hit ? hit.cls : (text.length > 8 ? "EVENT" : "IRRELEVANT");
    if (cls === "IRRELEVANT") {
      return { adopted: false, classification: cls, narrative: t("评论已记录", "Comment logged"), stats: zero };
    }
    const short = text.length > 30 ? text.slice(0, 30) + "…" : text;
    const tpl = {
      ITEM: [t("废墟深处，你翻出了评论区召唤的东西：", "Deep in the rubble, you dig out what chat summoned: "), { supply: 6 }],
      LOCATION: [t("地图边缘浮现出评论区提到的新地点：", "A new location from chat flickers onto the map: "), { sanity: 4 }],
      CHARACTER: [t("阴影里，评论区召唤的身影正朝你走来：", "From the shadows, the figure chat summoned starts toward you: "), { sanity: -3 }],
      EVENT: [t("风向突变——评论区的话应验了：", "The wind shifts — chat called it: "), { sanity: -2 }],
    }[cls];
    return { adopted: true, classification: cls, narrative: tpl[0] + t("「", "“") + short + t("」", "”"), stats: { ...zero, ...tpl[1] } };
  };

  const send = async () => {
    const text = val.trim();
    if (!text || quota <= 0) return;
    setVal(""); setKbUp(false); if (inputRef.current) inputRef.current.blur();

    // Own comment shows immediately; AI feedback follows
    const id = pushCmt({ user: nick || t("你", "You"), text, av: avatar }, { mine: true });

    let data = null;
    try {
      const res = await fetch("/api/comment", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ user: nick || t("幸存者", "Survivor"), text, lang: window.__LANG__ || "en" }),
      });
      if (res.status === 429) {
        const errData = await res.json().catch(() => ({}));
        setQuota(0);
        pushCmt({ text: "⚠ " + (errData.error || t("评论次数已用完", "Out of comments")) }, { sys: true });
        return;
      }
      if (res.ok) data = await res.json();
    } catch (e) { /* API unreachable — fall back below */ }

    if (data && data.remaining != null) setQuota(data.remaining);
    else setQuota((q) => q - 1);
    if (!data || data.adopted === undefined) {
      console.warn("[mobile] /api/comment unavailable — using local fallback");
      data = localClassify(text);
    }

    // Show AI feedback
    if (data.adopted) {
      // Inject straight into the embedded game (auto-script listens for this) —
      // no dependency on server-side buffer polling
      document.querySelectorAll(".feed-inner iframe").forEach((f) => {
        try {
          f.contentWindow.postMessage({
            type: "wl_adopted", user: nick || t("你", "You"), text,
            narrative: data.narrative, classification: data.classification, stats: data.stats,
          }, "*");
        } catch (e) {}
      });
      setStoryActive(true);
      setTimeout(() => {
        setComments((cs) => cs.map((x) => x.id === id ? { ...x, adopted: true } : x));
        const syncType = (data.classification || "event").toLowerCase();
        const syncName = data.narrative ? data.narrative.slice(0, window.__LANG__ === "en" ? 42 : 15) : text.slice(0, 10);
        pushCmt({}, { sync: { type: syncType, user: "@" + (nick || t("你", "You")), name: syncName } });
        setLikes((l) => l + Math.floor(Math.random() * 200) + 50);
        setTimeout(() => setStoryActive(false), 5000);
      }, 1500);
    } else {
      setTimeout(() => {
        pushCmt({ text: "📝 " + (data.narrative || t("评论已记录", "Comment logged")) }, { sys: true });
      }, 1000);
    }
  };

  const closeKb = () => { if (inputRef.current) inputRef.current.blur(); };

  const goFs = () => { setShowRotate(true); setTimeout(() => { setShowRotate(false); setFs(true); }, 900); };

  /* ---------- render pages ---------- */
  const StreamerWatch = (
    <span className="watch">{t("荒原阿陈", "Wasteland Chen")} · <b>{viewers.toLocaleString()}</b> {t("观看", "watching")}</span>
  );

  return (
    <div className="m-stage">
      <div className={"device " + (fs ? "landscape" : "")} ref={deviceRef}>
        <div className="notch" />
        <div className="screen">
          {!fs && (
            <div className="ios-bar">
              <span>{new Date().getHours().toString().padStart(2,"0")}:{new Date().getMinutes().toString().padStart(2,"0")}</span>
              <span className="r">📶 🔋</span>
            </div>
          )}

          {/* ---------- PAGE 1 · COVER ---------- */}
          {page === "cover" && !fs && (
            <div className="pg cover">
              <div className="sun" />
              <div className="embers">
                {Array.from({ length: 14 }).map((_, i) => (
                  <i key={i} style={{ left: (8 + i * 6.5) + "%", bottom: (120 + (i % 4) * 30) + "px",
                    animationDuration: (5 + (i % 5)) + "s", animationDelay: (i * 0.4) + "s" }} />
                ))}
              </div>
              <div className="skyline">
                {Array.from({ length: 11 }).map((_, i) => {
                  const broken = i % 3 === 1;
                  return (
                    <span key={i} className={broken ? "broken" : ""} style={{ height: (70 + (i * 41) % 150) + "px" }}>
                      {Array.from({ length: 3 }).map((_, j) => (i + j) % 2 ?
                        <i key={j} style={{ left: (6 + (j % 2) * 14) + "px", top: (14 + Math.floor(j) * 22) + "px" }} /> : null)}
                    </span>
                  );
                })}
              </div>
              <div className="ground" />

              <div className="c-top">
                <div className="kicker">{t("A I · 互 动 生 存 直 播", "AI · INTERACTIVE SURVIVAL")}</div>
                <div className="title">WASTELAND<span className="l2">LIVE</span></div>
                <div className="subtitle">{t("新时代来临", "A new era begins")}<br />{t("创造每一个直播剧情", "You write every twist of the stream")}</div>
                <div className="live-pill"><span className="dot" /> {t("直播进行中", "LIVE NOW")} · DAY 1 / 7</div>
              </div>

              <div className="c-btm">
                <button className="btn-glow" onClick={() => setPage("identity")}>{t("进 入 直 播 间", "JOIN THE STREAM")}</button>
                <div className="hint">{t("这片大陆会回应你的声音", "This wasteland answers your voice")}</div>
              </div>
            </div>
          )}

          {/* ---------- PAGE 2 · IDENTITY ---------- */}
          {page === "identity" && !fs && (
            <div className="pg identity">
              <div className="id-h">{t("⚙ 设 定 你 的 身 份", "⚙ CREATE YOUR ID")}</div>
              <div className="id-sub">{t("在废土里，代号就是你存在的证明。", "Out in the wasteland, your callsign is proof you exist.")}</div>

              <div className="id-label">{t("选择头像", "Pick an avatar")}</div>
              <div className="avatar-grid">
                {AVATARS.map((a) => (
                  <div key={a} className={"avatar-cell " + (avatar === a ? "sel" : "")} onClick={() => setAvatar(a)}>{a}</div>
                ))}
              </div>

              <div className="id-label">{t("你的代号", "Your callsign")}</div>
              <input className="id-input" value={nick} maxLength={12}
                onChange={(e) => setNick(e.target.value)} placeholder={t("输入你的代号", "Enter your callsign")} />

              <div className="id-note">{t("⚠ 当前为", "⚠ This is a ")}<b>{t("测试版", "beta")}</b>{t("，每位用户仅可发送 ", " — each user gets ")}<b>{t("5 条评论", "5 comments")}</b>{t("参与剧情生成。请把机会留给最关键的创意。", " to shape the story. Save them for your best ideas.")}</div>

              <div className="id-foot">
                <button className="btn-glow" onClick={enterRoom}>{t("进 入 末 日", "ENTER THE WASTELAND")}</button>
              </div>
            </div>
          )}

          {/* ---------- PAGE 3 · PORTRAIT ROOM ---------- */}
          {page === "room" && !fs && (
            <div className="pg room">
              <div className="room-top">
                <div className="streamer-chip">
                  <div className="av">🎮</div>
                  <div>
                    <div className="nm">{t("荒原阿陈", "Wasteland Chen")} <span className="live">LIVE</span></div>
                    <div className="watch">👁 <b>{viewers.toLocaleString()}</b> {t("观看", "watching")}</div>
                  </div>
                </div>
                <div className="like-chip"><span className="heart">❤</span> {(likes/1000).toFixed(1)}k</div>
              </div>

              <div className="feed-wrap" onClick={closeKb}>
                <div className="cd-bar">
                  {cdPhase === "collect" ? (
                    <React.Fragment>
                      <span className="cd-dot pulse" />
                      <span className="cd-label">💬 {t("评论收集中", "Collecting comments")}</span>
                      <span className="cd-time">{countdown}s</span>
                    </React.Fragment>
                  ) : (
                    <React.Fragment>
                      <span className="cd-dot deciding" />
                      <span className="cd-label">🎮 {t("主播决策中", "Streamer deciding")}</span>
                      <span className="cd-time">{countdown}s</span>
                    </React.Fragment>
                  )}
                </div>
                <div className="feed">
                  <GameFeed />
                </div>
                <button className="fs-hint" onClick={goFs}>⛶ {t("横屏看清剧情", "Go landscape for the story")}</button>
                <CommentWaterfall comments={comments} variant="portrait" storyActive={storyActive} />
              </div>

              <div className="room-input">
                {quota > 0 && quota < 5 && <div className="send-quota">{t("剩余 ", "")}{quota}{t(" 条", " left")}</div>}
                <div className={"box " + (kbUp ? "hot" : "")}>
                  <input ref={inputRef} value={val}
                    onChange={(e) => setVal(e.target.value)}
                    onFocus={() => setKbUp(true)}
                    onBlur={() => setKbUp(false)}
                    placeholder={quota > 0 ? t("说点什么影响剧情…", "Say something to shape the story…") : t("评论次数已用完", "Out of comments")}
                    onKeyDown={(e) => e.key === "Enter" && send()}
                    disabled={quota <= 0} />
                </div>
                <button className="send" onClick={send} disabled={quota <= 0 || !val.trim()}>➤</button>
              </div>

            </div>
          )}

          {/* ---------- PAGE 4 · LANDSCAPE FULLSCREEN ---------- */}
          {fs && (
            <div className="pg fs-room">
              <GameFeed landscape />
              <div className="fs-top">
                <div className="av">🎮</div>
                <div>
                  <div className="nm">{t("荒原阿陈", "Wasteland Chen")} <span style={{ color: "var(--red)", fontSize: 9 }}>● LIVE</span></div>
                </div>
                <span className="watch">👁 {viewers.toLocaleString()}</span>
              </div>
              <div className="fs-cd">
                {cdPhase === "collect" ? (
                  <React.Fragment><span className="cd-dot pulse" /><span>💬 {countdown}s</span></React.Fragment>
                ) : (
                  <React.Fragment><span className="cd-dot deciding" /><span>🎮 {countdown}s</span></React.Fragment>
                )}
              </div>
              <button className="fs-exit" onClick={() => setFs(false)}>⤡</button>
              <CommentWaterfall comments={comments} variant="land" storyActive={storyActive} />
              <div className="fs-input">
                <input ref={inputRef} value={val} onChange={(e) => setVal(e.target.value)}
                  placeholder={quota > 0 ? t("说点什么影响剧情…（剩余 ", "Say something to shape the story… (") + quota + t(" 条）", " left)") : t("评论次数已用完", "Out of comments")}
                  onKeyDown={(e) => e.key === "Enter" && send()} disabled={quota <= 0} />
                <button className="send" onClick={send} disabled={quota <= 0 || !val.trim()}>➤</button>
              </div>
            </div>
          )}

          {showRotate && (
            <div className="rotate-hint"><div className="ic">📱</div>{t("旋转中 · 进入全屏…", "Rotating · entering fullscreen…")}</div>
          )}
        </div>
      </div>
    </div>
  );
}

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