/* Root: routing, league/player polling, theme, draft submit. */

const POLL_MS = 4000;

function useLeagueState(leagueId) {
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const tick = React.useCallback(async () => {
    if (!leagueId) { setData(null); return; }
    try {
      const res = await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId));
      setData(res); setErr(null);
    } catch (e) {
      setErr(e.message);
      if (e.status === 404) setData(null);
    }
  }, [leagueId]);
  React.useEffect(() => {
    if (!leagueId) return;
    tick();
    const id = setInterval(tick, POLL_MS);
    return () => clearInterval(id);
  }, [leagueId, tick]);
  return { data, err, refresh: tick };
}

function usePlayers(leagueId) {
  const [players, setPlayers] = React.useState([]);
  const tick = React.useCallback(async () => {
    if (!leagueId) return;
    try {
      const res = await window.WC.api("/api/players?league_id=" + encodeURIComponent(leagueId));
      setPlayers((res.players || []).map(window.WC.normPlayer));
    } catch (e) { /* leave previous list */ }
  }, [leagueId]);
  React.useEffect(() => {
    if (!leagueId) return;
    tick();
    const id = setInterval(tick, POLL_MS);
    return () => clearInterval(id);
  }, [leagueId, tick]);
  return { players, refresh: tick };
}

/* Build the merged leagueState the play screens expect. */
function deriveLeagueState(raw, myMemberId) {
  if (!raw) return null;
  const { league, members, picks, on_the_clock, draft_order, total_picks } = raw;
  const managers = members.map((m) => window.WC.normMember(m, myMemberId));
  const mById = Object.fromEntries(managers.map(m => [m.id, m]));
  const orderIds = draft_order || [];
  const order = orderIds.map(id => mById[id]).filter(Boolean);

  const n = order.length || managers.length;
  const overall = league.current_pick | 0;
  const total = total_picks || (n * league.roster_size);
  const done = league.status === "done" || (total > 0 && overall >= total);
  const round = n > 0 ? Math.min(Math.floor(overall / n) + 1, league.roster_size) : 1;

  let roundOrder = [];
  if (order.length === n && n > 0) {
    const start = (round - 1) * n;
    const slice = order.slice(start, start + n);
    roundOrder = round % 2 === 1 ? slice : [...slice].reverse();
  }
  const onClock = on_the_clock ? (mById[on_the_clock] || null) : (done && order.length ? order[order.length - 1] : null);

  return {
    league, managers, picks,
    draft: { total, overall, done, round, onClock, roundOrder, order },
  };
}

function parseJoinFromUrl() {
  const params = new URLSearchParams(location.search);
  return params.get("join") || params.get("j");
}

// "?l=<league>&m=<member>" — restore identity on a fresh device.
function parseResumeFromUrl() {
  const params = new URLSearchParams(location.search);
  const l = params.get("l"), m = params.get("m");
  return l && m ? { leagueId: l, memberId: m } : null;
}

function RenameButton({ leagueId, memberId, currentName, onDone }) {
  const onClick = async () => {
    const next = prompt("Change your manager name:", currentName || "");
    if (next === null) return;
    const trimmed = next.trim();
    if (!trimmed) { alert("Name can't be blank."); return; }
    if (trimmed === currentName) return;
    try {
      await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId) + "/rename", {
        method: "POST",
        body: JSON.stringify({ member_id: memberId, display_name: trimmed }),
      });
      onDone && onDone();
    } catch (e) { alert("Couldn't rename: " + e.message); }
  };
  return (
    <button onClick={onClick} className="btn btn-soft btn-sm">
      ✏️ Edit my name
    </button>
  );
}

function SetPinButton({ leagueId, memberId, hasPin, onDone }) {
  const onClick = async () => {
    const action = hasPin
      ? prompt("Enter a new 4–6 digit PIN (or leave blank to remove it):", "")
      : prompt("Set a 4–6 digit recovery PIN. Used to get back in if you lose access:", "");
    if (action === null) return;
    const pin = action.trim();
    if (pin && !/^\d{4,6}$/.test(pin)) { alert("PIN must be 4–6 digits."); return; }
    try {
      await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId) + "/setpin", {
        method: "POST",
        body: JSON.stringify({ member_id: memberId, pin }),
      });
      alert(pin ? "PIN saved ✓" : "PIN cleared.");
      onDone && onDone();
    } catch (e) { alert("Couldn't set PIN: " + e.message); }
  };
  return (
    <button onClick={onClick} className="btn btn-soft btn-sm">
      🔒 {hasPin ? "Change my PIN" : "Set recovery PIN"}
    </button>
  );
}

// Exposed via window so screens_play.jsx can reuse these inline (Teams page).
function DeviceLinkButton({ leagueId, memberId }) {
  const [copied, setCopied] = React.useState(false);
  const link = location.origin + "/?l=" + encodeURIComponent(leagueId) + "&m=" + encodeURIComponent(memberId);
  const onClick = async () => {
    try { await navigator.clipboard.writeText(link); } catch (e) {}
    setCopied(true);
    setTimeout(() => setCopied(false), 1800);
  };
  return (
    <button onClick={onClick} className="btn btn-soft btn-sm" title="Use to access this league from another device">
      {copied ? "✓ Copied — open on any device" : "📱 Copy my access link"}
    </button>
  );
}

// Expose to screens_play.jsx (Teams page reuses these inline).
Object.assign(window, { RenameButton, SetPinButton, DeviceLinkButton });

function App() {
  const [theme, setThemeState] = React.useState(window.WC.STORE.getTheme());
  const [screen, setScreen] = React.useState("home");
  const [leagueId, setLeagueId] = React.useState(null);
  const [joinCode, setJoinCode] = React.useState(null);

  // On first mount: handle ?l=&m= (device resume), else ?join=, else resume last league.
  React.useEffect(() => {
    const resume = parseResumeFromUrl();
    if (resume) {
      window.WC.STORE.setMember(resume.leagueId, resume.memberId);
      window.WC.STORE.setCurrentLeague(resume.leagueId);
      setLeagueId(resume.leagueId);
      history.replaceState({}, "", location.pathname);
      return;
    }
    const join = parseJoinFromUrl();
    if (join) {
      setJoinCode(join);
      setScreen("join");
      history.replaceState({}, "", location.pathname);
      return;
    }
    const last = window.WC.STORE.getCurrentLeague();
    if (last && window.WC.STORE.getMember(last)) {
      setLeagueId(last);
    }
  }, []);

  const myMemberId = leagueId ? window.WC.STORE.getMember(leagueId) : null;
  const { data: rawLeague, err: leagueErr, refresh: refreshLeague } = useLeagueState(leagueId);

  // If the league no longer exists (deleted/stale localStorage), bail back to home.
  React.useEffect(() => {
    if (leagueId && leagueErr && rawLeague === null) {
      window.WC.STORE.clearCurrentLeague();
      setLeagueId(null);
      setScreen("home");
    }
  }, [leagueId, leagueErr, rawLeague]);

  const { players, refresh: refreshPlayers } = usePlayers(leagueId);
  const leagueState = React.useMemo(() => deriveLeagueState(rawLeague, myMemberId), [rawLeague, myMemberId]);

  // Apply theme on <html>. "system" resolves via matchMedia and updates live
  // when the OS flips (e.g. auto dark mode at sunset).
  React.useEffect(() => {
    window.WC.STORE.setTheme(theme); // persist the user's choice (incl. "system")
    const mql = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)");
    const resolved = () => theme === "system" ? (mql && mql.matches ? "dark" : "light") : theme;
    const apply = () => document.documentElement.setAttribute("data-theme", resolved());
    apply();
    if (theme === "system" && mql) {
      const handler = () => apply();
      mql.addEventListener("change", handler);
      return () => mql.removeEventListener("change", handler);
    }
  }, [theme]);

  // Auto-route based on league status. Draft done → land on Table; mid-draft → Draft; lobby → Lobby.
  React.useEffect(() => {
    if (!leagueState) return;
    const status = leagueState.league.status;
    if (screen === "home" || screen === "create" || screen === "join") {
      if (status === "lobby") setScreen("lobby");
      else if (status === "done") setScreen("leaderboard");
      else setScreen("draft");
    }
    if (screen === "lobby" && status !== "lobby") {
      setScreen(status === "done" ? "leaderboard" : "draft");
    }
    // Handle reset: league goes back to lobby from any in-game screen.
    if (["draft", "leaderboard", "teams", "players"].includes(screen) && status === "lobby") setScreen("lobby");
  }, [leagueState && leagueState.league.status]);

  const setTheme = (v) => setThemeState(v);
  const go = (s) => { setScreen(s); window.scrollTo({ top: 0, behavior: "instant" in window ? "instant" : "auto" }); };

  const enterLeague = (id) => { setLeagueId(id); setScreen("lobby"); };

  const leaveLeague = () => {
    if (!confirm("Leave this league? Your draft picks stay in the league.")) return;
    window.WC.STORE.clearCurrentLeague();
    setLeagueId(null);
    setScreen("home");
  };

  const startDraft = async (rosterSize) => {
    await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId) + "/start", {
      method: "POST",
      body: JSON.stringify({ roster_size: rosterSize }),
    });
    setScreen("draft");
  };

  const resetLeague = async (type) => {
    const msg = type === "full"
      ? "Reset the whole league back to lobby? All picks will be deleted."
      : "Restart the draft with a new random order? All picks will be deleted.";
    if (!confirm(msg)) return;
    await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId) + "/reset?type=" + type, {
      method: "POST",
      body: JSON.stringify({ member_id: myMemberId }),
    });
  };

  const pickPlayer = async (playerId) => {
    await window.WC.api("/api/leagues/" + encodeURIComponent(leagueId) + "/pick", {
      method: "POST",
      body: JSON.stringify({ member_id: myMemberId, player_id: playerId }),
    });
    refreshPlayers();
    // useLeagueState polls every 4s — we won't force-refresh here to avoid races with the tick.
  };

  // ---------- render ----------
  let body, navLeague = null;

  if (screen === "home" && !leagueId) {
    body = <Home go={go} />;
  } else if (screen === "create") {
    body = <CreateLeague go={go} onCreated={enterLeague} />;
  } else if (screen === "join") {
    body = <JoinLeague go={go} prefillCode={joinCode} onJoined={enterLeague} />;
  } else if (screen === "recover") {
    body = <RecoverAccess go={go} onRecovered={enterLeague} />;
  } else if (leagueId && !leagueState) {
    body = <Spinner label="Loading league…" />;
  } else if (leagueState) {
    const lg = leagueState.league;
    navLeague = { id: lg.id, name: lg.name };
    if (screen === "lobby" || lg.status === "lobby") {
      body = <Lobby league={lg} members={rawLeague.members} myMemberId={myMemberId} go={go} onStart={startDraft} onReset={resetLeague} />;
    } else if (screen === "leaderboard") {
      body = <Leaderboard leagueState={leagueState} players={players} go={go} />;
    } else if (screen === "teams") {
      body = <Teams leagueState={leagueState} players={players} />;
    } else if (screen === "players") {
      body = <AllPlayers leagueState={leagueState} players={players} />;
    } else {
      body = <Draft leagueState={leagueState} players={players} pickPlayer={pickPlayer} onReset={resetLeague} />;
    }
  } else {
    body = <Home go={go} />;
  }

  const showBar = screen !== "create" && screen !== "join" && screen !== "recover";
  const navScreen = (leagueState && leagueState.league.status === "lobby") ? null : navLeague;

  return (
    <div>
      {showBar && <TopBar screen={screen} go={go} league={navScreen} theme={theme} setTheme={setTheme} onLeave={leagueId ? leaveLeague : null} />}
      <ErrorBanner msg={leagueErr && leagueId ? leagueErr : null} />
      {body}
      {leagueId && (
        <div className="wrap row gap-2 wrap-flex" style={{ marginTop: -60, paddingTop: 0, paddingBottom: navScreen ? 84 : 20, justifyContent: "center" }}>
          {/* Account buttons are also on the Teams page in a prominent "Your account" card.
              Hide them from the footer there so they don't appear twice. */}
          {screen !== "teams" && myMemberId && rawLeague && (
            <RenameButton
              leagueId={leagueId}
              memberId={myMemberId}
              currentName={(rawLeague.members.find(m => m.id === myMemberId) || {}).display_name}
              onDone={refreshLeague}
            />
          )}
          {screen !== "teams" && myMemberId && rawLeague && (
            <SetPinButton
              leagueId={leagueId}
              memberId={myMemberId}
              hasPin={!!(rawLeague.members.find(m => m.id === myMemberId) || {}).has_pin}
              onDone={refreshLeague}
            />
          )}
          {myMemberId && <DeviceLinkButton leagueId={leagueId} memberId={myMemberId} />}
          <button onClick={leaveLeague} className="btn btn-soft btn-sm" style={{ color: "var(--muted)" }}>
            ← Leave league & create a new one
          </button>
        </div>
      )}
      {navScreen && <MobileNav screen={screen} go={go} />}
    </div>
  );
}

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