/* AcquiCup — prediction detail (score entry, X2 bonus, potential points) */
const { useState, useEffect, useRef, useMemo } = React;

// Re-render once when `targetMs` is reached so a time-based lock can flip live —
// a SINGLE timeout at the kickoff instant, not a perpetual interval. Returns "now"
// in ms. No tick is scheduled for a kickoff already passed or more than 24h out
// (the user won't sit on the page that long — a reload refreshes it). Used so the
// prediction form freezes the moment a match starts, matching the server lock.
function useNowUntil(targetMs) {
  const [now, setNow] = useState(() => Date.now());
  useEffect(() => {
    if (targetMs == null) return;
    const delay = targetMs - Date.now();
    if (delay <= 0 || delay > 86400000) return;
    const id = setTimeout(() => setNow(Date.now()), delay + 250);
    return () => clearTimeout(id);
  }, [targetMs]);
  return now;
}

function Stepper({ value, onChange, disabled }) {
  const set = (v) => !disabled && onChange(Math.max(0, Math.min(15, v)));
  return (
    <div className="col center gap-8 stepper">
      <button className="btn btn-ghost on-hero" disabled={disabled} onClick={() => set((+value || 0) + 1)}
        style={{ width: 44, height: 36, padding: 0, justifyContent: "center", borderRadius: 10 }}>
        <Icon name="chevronDown" size={18} style={{ transform: "rotate(180deg)" }} />
      </button>
      <div className="score-num" style={{ fontSize: 56, fontWeight: 700, width: 72, textAlign: "center",
        color: value === "" || value == null ? "color-mix(in srgb, var(--hero-ink) 45%, transparent)" : "var(--hero-ink)" }}>
        {value === "" || value == null ? "–" : value}
      </div>
      <button className="btn btn-ghost on-hero" disabled={disabled} onClick={() => set((+value || 0) - 1)}
        style={{ width: 44, height: 36, padding: 0, justifyContent: "center", borderRadius: 10 }}>
        <Icon name="chevronDown" size={18} />
      </button>
    </div>
  );
}

function BreakLine({ label, value, on, doubled }) {
  return (
    <div className="row between" style={{ padding: "9px 0", opacity: on ? 1 : .4 }}>
      <span style={{ fontSize: 13.5, color: on ? "var(--ink-2)" : "var(--ink-soft)" }}>{label}</span>
      <span className="mono" style={{ fontWeight: 600, fontSize: 13.5 }}>
        {on ? "+" + value : "—"}{doubled && on ? <span className="badge gold" style={{ marginLeft: 6, padding: "1px 6px" }}>×2</span> : null}
      </span>
    </div>
  );
}

function PredictionDetail({ match, store, back, save, openX2, removeX2 }) {
  const tz = useTimezone();
  const A = window.ACQ;
  const existing = store.predictions[match.id] || {};
  const settled = match.status === "finished";
  // A knockout fixture with placeholder participants (empty iso, e.g. "Winner
  // Match 73") has no real teams yet — not predictable until the bracket resolves.
  const tbd = isTbd(match);
  // Mirror the server's matchLock.isMatchEditable: a pick freezes BOTH when the
  // status leaves "upcoming" AND once the stored kickoff instant has passed. Status
  // alone is unsafe — nothing flips it automatically, so between real kickoff and the
  // next sync/admin status change a match sits in "upcoming" past its start. matchInstant()
  // is the client mirror of the server's kickoffTimestamp (interpreted in the source zone);
  // useNowUntil re-renders at kickoff so the form locks live without a refresh.
  const kickoffMs = matchInstant(match.date, match.time, matchSourceTz());
  const now = useNowUntil(kickoffMs);
  const started = kickoffMs != null && now >= kickoffMs;
  const editable = match.status === "upcoming" && !tbd && !started;
  const hasPick = existing.home != null;
  // Default to a 0–0 scoreline. It is NOT recorded until "Save pick" is pressed.
  const [home, setHome] = useState(hasPick ? existing.home : 0);
  const [away, setAway] = useState(hasPick ? existing.away : 0);
  const x2MatchIds = store.x2MatchIds || [];
  const x2Here = x2MatchIds.includes(match.id);
  const x2Remaining = Math.max(0, 2 - x2MatchIds.length);
  const x2Used = !x2Here && x2Remaining <= 0; // both bonuses spent elsewhere

  const outcome = outcomeOf(home, away);
  const ven = V(match.venue);

  // potential breakdown if this EXACT scoreline happens (outcome points + exact reward)
  const outcomePts = outcome ? match.points[outcome] : 0;
  const exactPts = outcome ? exactBonus(match, outcome) : 0;
  const subtotal = outcomePts + exactPts;
  const total = x2Here ? subtotal * 2 : subtotal;
  // Label reflects the exact-score mode: a ×N multiplier (default) or a flat +bonus.
  const exactLabel = match.exactScoreMode === "add"
    ? "Exact score bonus"
    : `Exact score (×${match.exactScoreMultiplier || 2})`;

  // A 0–0 default with no saved pick still needs saving; a saved pick only once edited.
  const dirty = !hasPick || +home !== existing.home || +away !== existing.away;
  const canSave = home !== "" && away !== "";

  function doSave() {
    save(match.id, { home: +home, away: +away });
    // Stay on the detail page so the "Saved" confirmation shows; the Back button
    // returns to the matches list.
  }

  return (
    <div className="col gap-20" style={{ maxWidth: 760, margin: "0 auto" }}>
      <button className="btn btn-ghost btn-sm" style={{ alignSelf: "flex-start" }} onClick={back}>
        <Icon name="chevron" size={14} style={{ transform: "rotate(180deg)" }} />Back to matches
      </button>

      {/* scoreboard */}
      <div className="card" style={{ overflow: "hidden" }}>
        <div className="row between" style={{ padding: "12px 18px", borderBottom: "1px solid var(--line-2)" }}>
          <div className="row gap-8">
            <span className="badge">{match.stage}{match.group ? " · Group " + match.group : ""}</span>
            <span className="muted" style={{ fontSize: 12.5 }}>{fmtMatchDay(match, tz)} · {fmtMatchTime(match, tz)} · {[ven.stadium, ven.city].filter(Boolean).join(", ")}</span>
          </div>
          <StatusPill status={tbd ? "tbd" : (started && match.status === "upcoming" ? "locked" : match.status)} minute={match.minute} />
        </div>

        <div className="pred-hero" style={{ background: "var(--hero-bg)", color: "var(--hero-ink)", padding: "26px 20px 28px", position: "relative" }}>
          <div className="row between center" style={{ gap: 6 }}>
            <div className="col center gap-10 grow"><TeamBadge code={match.home} size="lg" /><span style={{ fontWeight: 700, fontSize: 16 }}>{T(match.home).name}</span><span className="eyebrow" style={{ color: "color-mix(in srgb,var(--hero-ink) 60%,transparent)" }}>Home</span></div>
            {editable ? (
              <div className="row center" style={{ gap: 8 }}>
                <Stepper value={home} onChange={setHome} />
                <span className="score-num" style={{ fontSize: 40, opacity: .4 }}>:</span>
                <Stepper value={away} onChange={setAway} />
              </div>
            ) : (
              <div className="row center gap-12">
                <span className="score-num" style={{ fontSize: 60, fontWeight: 700 }}>{settled || match.status === "live" ? match.homeScore : "–"}</span>
                <span className="score-num" style={{ fontSize: 40, opacity: .4 }}>:</span>
                <span className="score-num" style={{ fontSize: 60, fontWeight: 700 }}>{settled || match.status === "live" ? match.awayScore : "–"}</span>
              </div>
            )}
            <div className="col center gap-10 grow"><TeamBadge code={match.away} size="lg" /><span style={{ fontWeight: 700, fontSize: 16 }}>{T(match.away).name}</span><span className="eyebrow" style={{ color: "color-mix(in srgb,var(--hero-ink) 60%,transparent)" }}>Away</span></div>
          </div>
          {!editable && existing.home != null && (
            <div className="row center" style={{ marginTop: 18 }}>
              <span className="badge" style={{ background: "color-mix(in srgb,var(--hero-ink) 14%,transparent)", color: "var(--hero-ink)" }}>
                Your prediction · {existing.home}–{existing.away}
              </span>
            </div>
          )}
        </div>

        {/* odds */}
        <div className="card-pad" style={{ padding: "16px 18px" }}>
          <div className="row between" style={{ marginBottom: 10 }}>
            <span className="eyebrow">Outcome points · odds-based</span>
            <span className="muted" style={{ fontSize: 12 }}>Bigger upset → bigger reward</span>
          </div>
          <OddsRow match={match} picked={outcome} size="lg" />
        </div>
      </div>

      {editable ? (
        <>
          {/* X2 */}
          <div className="card card-pad col gap-12" style={{ padding: "16px 18px",
            border: x2Here ? "1.5px solid var(--gold)" : "1px solid var(--line)",
            background: x2Here ? "color-mix(in srgb, var(--brand-yellow) 12%, var(--surface))" : "var(--surface)" }}>
            <div className="row between">
              <div className="row gap-12">
                <div style={{ width: 40, height: 40, borderRadius: 11, display: "flex", alignItems: "center", justifyContent: "center",
                  background: x2Here ? "var(--brand-yellow)" : "var(--chip-bg)", color: x2Here ? "#5a4400" : "var(--ink-2)" }}>
                  <Icon name="bolt" size={20} fill />
                </div>
                <div className="col" style={{ lineHeight: 1.3 }}>
                  <span style={{ fontWeight: 700, fontSize: 15 }}>X2 Bonus {x2Here && <span className="badge gold" style={{ marginLeft: 4 }}>Active here</span>}</span>
                  <span className="muted" style={{ fontSize: 12.5 }}>Two per tournament · doubles every point this match earns.</span>
                </div>
              </div>
              {x2Here
                ? <button className="btn btn-ghost btn-sm" onClick={() => removeX2 && removeX2(match.id)}>Remove</button>
                : x2Used
                  ? <span className="badge" style={{ whiteSpace: "nowrap" }}>Both used</span>
                  : <button className="btn btn-soft btn-sm" onClick={() => openX2(match.id)}>Use X2 here</button>}
            </div>
            {!x2Here && x2MatchIds.length > 0 && (
              <div className="row gap-8 muted" style={{ fontSize: 12.5, borderTop: "1px solid var(--line-2)", paddingTop: 10 }}>
                <Icon name="lock" size={13} />
                {x2Used ? "Both X2 bonuses are on " : "1 of 2 X2 bonuses on "}
                {x2MatchIds.map((id, i) => { const mm = A.MATCHES.find((x) => x.id === id); const lbl = mm ? `${T(mm.home).code}–${T(mm.away).code}` : "another match"; return (i === 0 ? "" : ", ") + lbl; }).join("")}
                {x2Used ? ". Remove one (while its match is open) to move it." : "."}
              </div>
            )}
          </div>

          {/* potential points */}
          <div className="card card-pad col" style={{ padding: "16px 18px" }}>
            <div className="row between" style={{ marginBottom: 4 }}>
              <span className="eyebrow">If this exact result happens</span>
              {x2Here && <span className="badge gold mono"><Icon name="bolt" size={11} fill />X2 doubling</span>}
            </div>
            <BreakLine label={`Correct outcome (${outcome === "home" ? T(match.home).name : outcome === "away" ? T(match.away).name : outcome === "draw" ? "Draw" : "pick a score"})`} value={outcomePts} on={!!outcome} doubled={x2Here} />
            <hr className="hr" style={{ opacity: .5 }} />
            <BreakLine label={exactLabel} value={exactPts} on={!!outcome} doubled={x2Here} />
            <div className="row between" style={{ marginTop: 12, paddingTop: 14, borderTop: "1.5px solid var(--line)" }}>
              <span style={{ fontWeight: 700, fontSize: 15 }}>Maximum potential</span>
              <span className="mono" style={{ fontWeight: 700, fontSize: 26, color: "var(--accent)" }}>{total}<span className="muted" style={{ fontSize: 13, fontWeight: 500 }}> pts</span></span>
            </div>
            <span className="muted" style={{ fontSize: 11.5, marginTop: 6 }}>You still earn the outcome points for the correct winner even if the exact score is off.</span>
          </div>

          <div className="row between wrap gap-12 card card-pad" style={{ padding: "13px 16px", marginTop: 2 }}>
            <span className="muted" style={{ fontSize: 12.5 }}><Icon name="lock" size={12} style={{ verticalAlign: "-2px" }} /> Editable until kickoff · {fmtMatchTime(match, tz)}</span>
            <div className="row gap-10">
              <button className="btn btn-ghost" onClick={back}>Back</button>
              {dirty
                ? <button className={"btn " + (hasPick ? "btn-primary" : "btn-danger")} disabled={!canSave} onClick={doSave}>{hasPick ? "Update pick" : "Save pick"}<Icon name="check" size={15} stroke={2.4} /></button>
                : <span className="badge pos mono" style={{ padding: "9px 14px" }}><Icon name="check" size={14} stroke={2.5} />Saved</span>}
            </div>
          </div>
        </>
      ) : (
        /* read-only settled / locked */
        <>
          <ResultPanel match={match} pred={existing} x2Here={x2Here} />
          {(settled || match.status === "live") && <MatchPredictionsCard match={match} store={store} />}
        </>
      )}
    </div>
  );
}

function ResultPanel({ match, pred, x2Here }) {
  const settled = match.status === "finished";
  if (!pred || pred.home == null) {
    return <div className="card card-pad col center gap-8" style={{ padding: 34, textAlign: "center" }}>
      <Icon name="lock" size={22} style={{ color: "var(--ink-soft)" }} />
      <span style={{ fontWeight: 700 }}>Prediction locked</span>
      <span className="muted" style={{ fontSize: 13 }}>This match started before you submitted a prediction. No points — but no penalty either.</span>
    </div>;
  }
  // Finished → the settled `earned` breakdown; in play → the server's provisional
  // `live` breakdown, scored against the score as it stands right now.
  const inPlay = match.status === "live";
  const e = settled ? pred.earned : inPlay ? pred.live : null;
  if (!e) {
    return <div className="card card-pad col center gap-8" style={{ padding: 30, textAlign: "center" }}>
      <Icon name={inPlay ? "whistle" : "lock"} size={22} style={{ color: "var(--ink-soft)" }} />
      <span style={{ fontWeight: 700 }}>{inPlay ? "Match in play — prediction locked" : "Prediction locked"}</span>
      <span className="muted" style={{ fontSize: 13 }}>Your {pred.home}–{pred.away} is in. Points settle when the match finishes.</span>
    </div>;
  }
  return (
    <div className="card card-pad col" style={{ padding: "16px 18px" }}>
      <span className="eyebrow row gap-6" style={{ marginBottom: 6, alignItems: "center" }}>
        {inPlay && <span className="live-dot" style={{ width: 6, height: 6 }}></span>}
        {inPlay ? `Live · if it ends ${match.homeScore}–${match.awayScore}` : "Your result"}
      </span>
      <BreakLine label="Correct outcome" value={e.outcome} on={e.outcome > 0} doubled={x2Here} />
      <hr className="hr" style={{ opacity: .5 }} />
      <BreakLine label={match.exactScoreMode === "add" ? "Exact score bonus" : `Exact score (×${match.exactScoreMultiplier || 2})`} value={e.exact} on={!!e.isExact} doubled={x2Here} />
      <div className="row between" style={{ marginTop: 12, paddingTop: 14, borderTop: "1.5px solid var(--line)" }}>
        <span style={{ fontWeight: 700, fontSize: 15 }}>{inPlay ? "Live points" : "Points earned"}</span>
        <span className="mono" style={{ fontWeight: 700, fontSize: 26, color: inPlay ? "var(--live-tx)" : "var(--pos-tx)" }}>+{e.total}</span>
      </div>
      {inPlay && <span className="muted" style={{ fontSize: 11.5, marginTop: 6 }}>Provisional — your points move with the score and settle at full time.</span>}
    </div>
  );
}

/* Every player's pick on a revealed (live/finished) match — the table behind the
   match-card "Details"/"View result" button. Fetched on open from
   GET /api/matches/:id/predictions (the server refuses pre-kickoff, so pending bets
   never leak); names/companies/AI flags are joined from the USERS list already in
   window.ACQ. Collapsed view = the top 10 rows PLUS every AI bot and the viewer's own
   row wherever they sit (with ··· gap markers); "Show all" expands to the full field. */
function MatchPredictionsCard({ match, store }) {
  const A = window.ACQ;
  const [rows, setRows] = useState(null); // null = loading
  const [err, setErr] = useState(null);
  const [expanded, setExpanded] = useState(false);
  const inPlay = match.status === "live";

  useEffect(() => {
    let on = true;
    setRows(null); setErr(null);
    API.getMatchPredictions(match.id)
      .then((r) => { if (on) setRows((r && r.predictions) || []); })
      .catch((e) => { if (on) setErr((e && e.error) || "Could not load predictions."); });
    return () => { on = false; };
    // Re-fetch when the public score moves so live provisional points stay current.
  }, [match.id, match.status, match.homeScore, match.awayScore]);

  // Server rows carry only the pick + points keyed by userId — join the display
  // identity (name, company, AI badge, `you`) from the bootstrap USERS list.
  const byId = useMemo(() => {
    const m = {};
    (A.USERS || []).forEach((u) => { m[u.id] = u; });
    return m;
  }, [A.USERS]);
  const all = useMemo(
    () => (rows || []).map((r) => ({ ...r, u: byId[r.userId] })).filter((r) => r.u),
    [rows, byId]
  );

  const TOP_N = 10;
  // The server sorts best-first, so position = array index. Collapsed keeps top 10 + AI + me.
  const visible = expanded ? all : all.filter((r, i) => i < TOP_N || r.u.isAi || r.u.you);
  const hidden = all.length - visible.length;
  const posOf = useMemo(() => { const m = {}; all.forEach((r, i) => { m[r.userId] = i + 1; }); return m; }, [all]);

  return (
    <div className="card" style={{ overflow: "hidden" }}>
      <div className="row between wrap gap-8" style={{ padding: "14px 18px", borderBottom: "1px solid var(--line-2)" }}>
        <span className="eyebrow row gap-6" style={{ alignItems: "center" }}>
          {inPlay && <span className="live-dot" style={{ width: 6, height: 6 }}></span>}
          All predictions{rows ? ` · ${all.length} player${all.length === 1 ? "" : "s"}` : ""}
        </span>
        {inPlay && <span className="muted" style={{ fontSize: 11.5 }}>Provisional — points move with the score</span>}
      </div>

      {err ? (
        <div className="card-pad muted" style={{ padding: 22, textAlign: "center", fontSize: 13 }}>{err}</div>
      ) : rows == null ? (
        <div className="card-pad muted" style={{ padding: 22, textAlign: "center", fontSize: 13 }}>Loading predictions…</div>
      ) : all.length === 0 ? (
        <div className="card-pad muted" style={{ padding: 22, textAlign: "center", fontSize: 13 }}>Nobody predicted this match.</div>
      ) : (
        <>
          <div style={{ overflowX: "auto" }}>
            <table className="lb" style={{ width: "100%" }}>
              <thead><tr>
                <th style={{ width: 44 }}>#</th>
                <th>Player</th>
                <th style={{ textAlign: "center", width: 90 }}>Pick</th>
                <th style={{ textAlign: "right", width: 96 }}>Points</th>
              </tr></thead>
              <tbody>
                {visible.map((r, ri) => {
                  const pos = posOf[r.userId];
                  const prevPos = ri > 0 ? posOf[visible[ri - 1].userId] : 0;
                  const gap = pos - prevPos > 1; // collapsed view skipped rows here
                  return (
                    <React.Fragment key={r.userId}>
                      {gap && <tr className="lb-gap"><td colSpan={4} style={{ textAlign: "center", color: "var(--ink-soft)", padding: "4px 0" }}>···</td></tr>}
                      <tr className={"hov " + (r.u.you ? "me-row" : "")}
                        style={{ cursor: store && store.openUser ? "pointer" : undefined }}
                        onClick={() => store && store.openUser && store.openUser(r.u)}>
                        <td><span className="rank-num">{pos}</span></td>
                        <td>
                          <span className="row gap-8" style={{ alignItems: "center", minWidth: 0 }}>
                            <CompanyLogo id={r.u.company} size={22} />
                            <span style={{ fontWeight: 700, fontSize: 14, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{userName(r.u)}{r.u.you ? " · you" : ""}</span>
                            {r.u.isAi && <AiBadge />}
                          </span>
                        </td>
                        <td style={{ textAlign: "center" }}>
                          <span className="row mono" style={{ gap: 6, alignItems: "center", justifyContent: "center", fontWeight: 600, whiteSpace: "nowrap" }}>
                            {r.home}–{r.away}
                            {r.x2 && <span className="badge gold" style={{ padding: "1px 5px", fontSize: 10 }}><Icon name="bolt" size={9} fill />X2</span>}
                          </span>
                        </td>
                        <td style={{ textAlign: "right" }}>
                          {r.total != null ? (
                            <span className="col" style={{ alignItems: "flex-end", gap: 2 }}>
                              <span className="mono" style={{ fontWeight: 700, fontSize: 15, color: r.live ? "var(--live-tx)" : r.total > 0 ? "var(--pos-tx)" : "var(--ink-soft)" }}>+{r.total}</span>
                              {r.isExact && <span className="badge gold" style={{ padding: "1px 6px", fontSize: 9.5 }}>Exact</span>}
                            </span>
                          ) : (
                            <span className="muted mono">–</span>
                          )}
                        </td>
                      </tr>
                    </React.Fragment>
                  );
                })}
              </tbody>
            </table>
          </div>
          {(hidden > 0 || expanded) && (
            <div className="row center" style={{ padding: "10px 0 14px" }}>
              <button className="btn btn-ghost btn-sm" onClick={() => setExpanded((x) => !x)}>
                {expanded ? "Show fewer" : `Show all ${all.length} players`}
                <Icon name="chevronDown" size={13} style={expanded ? { transform: "rotate(180deg)" } : undefined} />
              </button>
            </div>
          )}
        </>
      )}
    </div>
  );
}

Object.assign(window, { PredictionDetail });
