/* Player app — mission, round table, scoreboard, feed, traitor tools */
(function () {
  const { useState, useEffect, useRef } = React;
  const S = () => window.TraitorsStore;

  function relTime(t) {
    if (!t || !t.seconds) return "";
    const d = Date.now() / 1000 - t.seconds;
    if (d < 60) return "just now";
    if (d < 3600) return Math.floor(d / 60) + "m ago";
    if (d < 86400) return Math.floor(d / 3600) + "h ago";
    return Math.floor(d / 86400) + "d ago";
  }
  const STATUS_LABEL = {
    roles_assigned: "Roles dealt", mission: "Mission", conclave: "Nightfall",
    round_table: "Round Table", results: "Results", game_over: "Game over",
  };

  function isIOS() { return /iphone|ipad|ipod/i.test(navigator.userAgent); }
  function isStandalone() {
    return window.navigator.standalone === true ||
      (window.matchMedia && window.matchMedia("(display-mode: standalone)").matches);
  }

  /* ---- enable-alerts / iOS install hint ---- */
  function AlertsControl({ snap }) {
    const perm = snap.fcmPermission;
    if (perm === "granted") return null;
    if (isIOS() && !isStandalone()) {
      return <span className="t-pill" title="Add to Home Screen, then open from there to get alerts.">↑ Add to Home Screen for alerts</span>;
    }
    if (perm === "unsupported") return null;
    return (
      <button className="t-pill t-pill--gold" onClick={() => S().enableNotifications()}>🔔 Enable alerts</button>
    );
  }

  function PlayerTopBar({ snap }) {
    const g = snap.game;
    return (
      <div className="t-spread" style={{ padding: "16px 20px 6px" }}>
        <div>
          <div className="t-kicker" style={{ marginBottom: 3 }}>
            {STATUS_LABEL[g.status] || "In play"}{snap.isTraitor ? " · Traitor" : ""}
          </div>
          <div style={{ fontWeight: 900, fontSize: "1.05rem" }}>{g.name}</div>
        </div>
        <AlertsControl snap={snap} />
      </div>
    );
  }

  /* ---- Mission tab ---- */
  function MissionTab({ snap }) {
    const m = snap.activeMission;
    const tasks = snap.secretTasks.filter((t) => !m || !t.missionId || t.missionId === m.id);
    if (!m) {
      return <EmptyState icon="✚" title="No mission yet" body="Your leader will set the next challenge. Stand by." />;
    }
    return (
      <div className="t-stack" style={{ gap: 16, padding: "4px 20px 20px" }}>
        <div className="t-card t-pad">
          <p className="t-eyebrow" style={{ marginBottom: 8 }}>The Mission</p>
          <h2 className="t-h2" style={{ fontSize: "1.5rem", marginBottom: 10 }}>{m.title}</h2>
          <p className="t-body" style={{ whiteSpace: "pre-wrap" }}>{m.publicRules || "Listen to your leader for the rules."}</p>
          {m.pointsForCompletion ? (
            <div style={{ marginTop: 14 }}><Pill kind="gold">+{m.pointsForCompletion} points</Pill></div>
          ) : null}
        </div>
        {snap.isTraitor && (
          <div className="t-card t-pad" style={{ border: "1px solid var(--t-traitor-deep)", background: "radial-gradient(120% 90% at 50% 0%, rgba(110,15,20,.4), var(--t-panel) 65%)" }}>
            <p className="t-eyebrow" style={{ color: "var(--t-traitor-glow)", marginBottom: 8 }}>✦ Traitors only — your secret task</p>
            {tasks.length ? tasks.map((t) => (
              <div key={t.id} style={{ marginBottom: 10 }}>
                <p className="t-body" style={{ color: "var(--t-fg)" }}>{t.description}</p>
                {t.pointsValue ? <Pill kind="red">+{t.pointsValue} if undetected</Pill> : null}
              </div>
            )) : <p className="t-body">No secret task this mission — blend in and stay above suspicion.</p>}
          </div>
        )}
      </div>
    );
  }

  /* ---- Round Table / voting tab ---- */
  function VoteTab({ snap }) {
    const round = snap.round;
    const players = snap.players;
    const me = snap.me;
    const [busy, setBusy] = useState(null);

    if (!round) {
      return <EmptyState icon="☀" title="Round Table closed" body="When your leader opens the Round Table, you'll vote here." />;
    }
    if (round.revealed && round.tally) {
      const rows = Object.entries(round.tally)
        .map(([uid, c]) => ({ player: players.find((p) => p.id === uid), count: c }))
        .filter((r) => r.player)
        .sort((a, b) => b.count - a.count);
      return (
        <div className="t-stack" style={{ gap: 14, padding: "4px 20px 20px" }}>
          <div style={{ textAlign: "center", margin: "6px 0 4px" }}><PhaseBanner phase="day" round={null} /></div>
          <p className="t-body t-center" style={{ marginBottom: 4 }}>The votes are revealed.</p>
          {rows.map((r) => {
            const fingered = (round.fingered || []).includes(r.player.id);
            return (
              <div key={r.player.id} className="t-card" style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 14px", border: fingered ? "1px solid var(--t-gold)" : "1px solid var(--t-line)" }}>
                <Avatar player={r.player} size={38} />
                <span style={{ flex: 1, fontWeight: 800 }}>{r.player.name}</span>
                <span style={{ fontWeight: 900, color: "var(--t-gold)", fontSize: "1.1rem" }}>{r.count}</span>
              </div>
            );
          })}
          {!rows.length && <EmptyState icon="∅" title="No votes were cast" body="" />}
        </div>
      );
    }
    if (round.status !== "open") {
      return <EmptyState icon="⏳" title="Votes are in" body="Awaiting the reveal from your leader." />;
    }
    const candidates = players.filter((p) => p.id !== (me && me.id));
    return (
      <div className="t-stack" style={{ gap: 12, padding: "4px 20px 20px" }}>
        <div style={{ textAlign: "center", margin: "6px 0" }}><PhaseBanner phase="day" round={null} /></div>
        <p className="t-body t-center" style={{ marginBottom: 6 }}>
          {snap.myVote ? "Your vote is in — tap another to change it." : "Who do you suspect is a Traitor?"}
        </p>
        {candidates.map((p) => (
          <PlayerTile key={p.id} player={p} selected={snap.myVote === p.id}
            disabled={busy === p.id}
            onPick={async () => { setBusy(p.id); try { await S().castVote(p.id); } catch (e) {} setBusy(null); }} />
        ))}
      </div>
    );
  }

  /* ---- Scoreboard tab ---- */
  function ScoresTab({ snap }) {
    const rows = snap.players.slice().sort((a, b) => b.score - a.score);
    const me = snap.me;
    return (
      <div className="t-stack" style={{ gap: 10, padding: "4px 20px 20px" }}>
        <p className="t-eyebrow t-center" style={{ margin: "6px 0 10px" }}>The Scoreboard</p>
        {rows.map((p, i) => {
          const mine = me && p.id === me.id;
          return (
            <div key={p.id} className="t-card" style={{
              display: "flex", alignItems: "center", gap: 12, padding: "10px 14px",
              border: mine ? "1px solid var(--t-gold)" : "1px solid var(--t-line)",
            }}>
              <span style={{ width: 22, textAlign: "center", fontWeight: 900, color: i < 3 ? "var(--t-gold)" : "var(--t-fg3)" }}>{i + 1}</span>
              <Avatar player={p} size={38} />
              <span style={{ flex: 1, fontWeight: 800 }}>{p.name}{mine ? " · you" : ""}{p.murdered ? " · murdered" : ""}</span>
              <span style={{ fontWeight: 900, fontSize: "1.15rem", color: "var(--t-fg)" }}>{p.score}</span>
            </div>
          );
        })}
      </div>
    );
  }

  /* ---- Activity feed tab ---- */
  function FeedTab({ snap }) {
    if (!snap.events.length) return <EmptyState icon="✦" title="All quiet" body="The castle holds its breath…" />;
    return (
      <div className="t-stack" style={{ gap: 8, padding: "4px 20px 20px" }}>
        {snap.events.map((e) => (
          <div key={e.id} className="t-card" style={{ padding: "11px 14px" }}>
            <p className="t-body" style={{ color: "var(--t-fg)", fontSize: ".92rem" }}>{e.message}</p>
            <p className="t-muted" style={{ fontSize: ".68rem", marginTop: 3 }}>{relTime(e.createdAt)}</p>
          </div>
        ))}
      </div>
    );
  }

  /* ---- Traitor tab: murder + chat ---- */
  function TraitorTab({ snap }) {
    const players = snap.players;
    const conclave = snap.game.status === "conclave";
    const candidates = players.filter((p) => p.id !== snap.me.id && !p.murdered);
    const [text, setText] = useState("");
    const scroller = useRef(null);
    useEffect(() => { if (scroller.current) scroller.current.scrollTop = scroller.current.scrollHeight; }, [snap.traitorChat.length]);

    const nameOf = (uid) => { const p = players.find((x) => x.id === uid); return p ? p.name : "someone"; };

    return (
      <div className="t-stack" style={{ flex: 1, minHeight: 0, padding: "4px 16px 0" }}>
        <div style={{ textAlign: "center", margin: "4px 0 10px" }}>
          <Pill kind="red">✦ Traitors only · the GM can see this</Pill>
        </div>

        {conclave && (
          <div className="t-card t-pad" style={{ marginBottom: 12 }}>
            <p className="t-eyebrow" style={{ color: "var(--t-traitor-glow)", marginBottom: 8 }}>Choose tonight's victim</p>
            {candidates.map((p) => (
              <div key={p.id} style={{ marginBottom: 8 }}>
                <PlayerTile player={p} onPick={async () => { try { await S().proposeMurder(p.id); } catch (e) {} }} />
              </div>
            ))}
            {snap.murderProposals.length > 0 && (
              <p className="t-muted" style={{ fontSize: ".8rem", marginTop: 8 }}>
                Proposed: {snap.murderProposals.map((m) => nameOf(m.targetUid)).join(", ")} — your GM confirms the kill.
              </p>
            )}
          </div>
        )}

        <p className="t-kicker" style={{ marginBottom: 6 }}>Traitor chat</p>
        <div ref={scroller} className="t-scroll" style={{ flex: 1, minHeight: 120, display: "flex", flexDirection: "column", gap: 8, paddingBottom: 10 }}>
          {snap.traitorChat.map((m) => {
            const mine = m.senderUid === snap.me.id;
            return (
              <div key={m.id} style={{ alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "82%" }}>
                {!mine && <div className="t-muted" style={{ fontSize: ".66rem", marginBottom: 2, paddingLeft: 4 }}>{m.senderName}</div>}
                <div style={{
                  padding: "9px 13px", borderRadius: 14, fontSize: ".92rem",
                  background: mine ? "var(--t-traitor-deep)" : "var(--t-panel2)",
                  color: "var(--t-fg)", border: "1px solid var(--t-line)",
                }}>{m.text}</div>
              </div>
            );
          })}
          {!snap.traitorChat.length && <p className="t-muted t-center" style={{ marginTop: 20 }}>Plot in secret…</p>}
        </div>
        <div style={{ display: "flex", gap: 8, padding: "8px 0 calc(8px + env(safe-area-inset-bottom))" }}>
          <input className="t-field" style={{ flex: 1, padding: "12px 14px" }} value={text} maxLength={500}
            placeholder="Message your fellow traitors" onChange={(e) => setText(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter" && text.trim()) { S().sendTraitorChat(text); setText(""); } }} />
          <button className="t-btn t-btn--danger t-btn--sm" disabled={!text.trim()}
            onClick={() => { S().sendTraitorChat(text); setText(""); }}>Send</button>
        </div>
      </div>
    );
  }

  /* ---- murdered overlay ---- */
  function MurderedOverlay({ onClose }) {
    return (
      <div style={{ position: "fixed", inset: 0, zIndex: 70, background: "rgba(5,3,9,.92)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 28, textAlign: "center" }}>
        <div className="t-enter">
          <div style={{ fontSize: "3.4rem", color: "var(--t-traitor-glow)", marginBottom: 10 }}>✦</div>
          <h1 className="t-h1" style={{ fontSize: "2.6rem", color: "var(--t-traitor-glow)", textShadow: "0 0 40px rgba(255,59,70,.5)" }}>Murdered</h1>
          <p className="t-body" style={{ maxWidth: 320, margin: "14px auto 0" }}>
            The Traitors came for you in the night. You stay in the game — keep playing for points, but the night was not kind.
          </p>
          <button className="t-btn t-btn--ghost" style={{ maxWidth: 280, margin: "26px auto 0" }} onClick={onClose}>Continue</button>
        </div>
      </div>
    );
  }

  function EmptyState({ icon, title, body }) {
    return (
      <div className="t-screen t-center" style={{ gap: 10 }}>
        <div style={{ fontSize: "2.4rem", color: "var(--t-gold-dim)" }}>{icon}</div>
        <h2 className="t-h2" style={{ fontSize: "1.4rem" }}>{title}</h2>
        {body && <p className="t-body" style={{ maxWidth: 280 }}>{body}</p>}
      </div>
    );
  }

  function NavBtn({ id, label, icon, active, onClick }) {
    return (
      <button onClick={() => onClick(id)} style={{
        appearance: "none", border: 0, background: "transparent", cursor: "pointer",
        flex: 1, padding: "9px 4px calc(9px + env(safe-area-inset-bottom))", fontFamily: "inherit",
        color: active ? "var(--t-gold)" : "var(--t-fg3)",
      }}>
        <div style={{ fontSize: "1.2rem", lineHeight: 1 }}>{icon}</div>
        <div style={{ fontSize: ".62rem", fontWeight: 800, letterSpacing: ".08em", textTransform: "uppercase", marginTop: 4 }}>{label}</div>
      </button>
    );
  }

  function PlayerApp({ snap }) {
    const status = snap.game.status;
    const [tab, setTab] = useState("mission");
    const [murderSeen, setMurderSeen] = useState(false);

    // follow the GM's stage changes
    useEffect(() => {
      if (status === "round_table" || status === "results") setTab("vote");
      else if (status === "conclave" && snap.isTraitor) setTab("traitors");
      else if (status === "mission") setTab("mission");
      else if (status === "game_over") setTab("scores");
    }, [status]);

    let body;
    if (tab === "mission") body = <MissionTab snap={snap} />;
    else if (tab === "vote") body = <VoteTab snap={snap} />;
    else if (tab === "scores") body = <ScoresTab snap={snap} />;
    else if (tab === "feed") body = <FeedTab snap={snap} />;
    else if (tab === "traitors") body = <TraitorTab snap={snap} />;

    const showMurder = snap.me && snap.me.murdered && !murderSeen;

    return (
      <div className="t-stack" style={{ flex: 1, minHeight: 0 }}>
        <PlayerTopBar snap={snap} />
        <div className="t-scroll" style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>{body}</div>
        <div style={{ display: "flex", borderTop: "1px solid var(--t-line)", background: "var(--t-bg)" }}>
          <NavBtn id="mission" label="Mission" icon="✚" active={tab === "mission"} onClick={setTab} />
          <NavBtn id="vote" label="Vote" icon="☀" active={tab === "vote"} onClick={setTab} />
          <NavBtn id="scores" label="Scores" icon="♛" active={tab === "scores"} onClick={setTab} />
          <NavBtn id="feed" label="Feed" icon="✦" active={tab === "feed"} onClick={setTab} />
          {snap.isTraitor && <NavBtn id="traitors" label="Traitors" icon="☾" active={tab === "traitors"} onClick={setTab} />}
        </div>
        {showMurder && <MurderedOverlay onClose={() => setMurderSeen(true)} />}
      </div>
    );
  }

  /* ---- player lobby (waiting room before roles are dealt) ---- */
  function PlayerLobby({ snap }) {
    return (
      <div className="t-stack" style={{ flex: 1, minHeight: 0 }}>
        <PlayerTopBar snap={snap} />
        <div className="t-screen t-center" style={{ gap: 14 }}>
          <Candle scale={1.4} />
          <p className="t-eyebrow">You're in</p>
          <h2 className="t-h2">Welcome, {snap.me ? snap.me.name : "player"}</h2>
          <p className="t-body" style={{ maxWidth: 300 }}>
            {snap.players.length} player{snap.players.length === 1 ? "" : "s"} have entered the castle. Wait for your leader to deal the roles…
          </p>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 8, justifyContent: "center", marginTop: 6 }}>
            {snap.players.map((p) => <Avatar key={p.id} player={p} size={36} />)}
          </div>
          <div style={{ marginTop: 18 }}><AlertsControl snap={snap} /></div>
        </div>
      </div>
    );
  }

  Object.assign(window, { PlayerApp, PlayerLobby });
})();
