import { useCallback, useEffect, useMemo, useState } from 'react';
import {
  api,
  formatCredits,
  formatLastConnection,
  formatPlayTime,
  compareCents,
  creditsToCentsString,
  toCentsBigInt,
} from '../api';

/** Credits delta (e.g. "15.5" or "-1000") → signed cents string. */
function parseDeltaCents(raw) {
  const s = String(raw ?? '').trim().replace(',', '.');
  if (!s || s === '0' || s === '+0' || s === '-0') return null;
  const neg = s.startsWith('-');
  const body = s.startsWith('+') || s.startsWith('-') ? s.slice(1) : s;
  const cents = creditsToCentsString(body);
  if (cents == null || cents === '0') return null;
  return neg ? `-${cents}` : cents;
}

/** Whole-unit delta (Pr / osu) — integers only. */
function parseDeltaUnits(raw) {
  const s = String(raw ?? '').trim();
  if (!/^-?\d+$/.test(s) || s === '0' || s === '-0') return null;
  try {
    return BigInt(s);
  } catch {
    return null;
  }
}

function balanceAfterDelta(balance, delta) {
  try {
    const next = toCentsBigInt(balance) + toCentsBigInt(delta);
    return (next < 0n ? 0n : next).toString();
  } catch {
    return toCentsBigInt(balance).toString();
  }
}

/** Compact display for whole units (Pr / osu) via credit formatter. */
function formatUnits(n) {
  try {
    return formatCredits((BigInt(n) * 100n).toString());
  } catch {
    return String(n);
  }
}

function previewClass(delta) {
  if (delta == null) return 'admin-adjust-preview muted';
  const n = typeof delta === 'bigint' ? delta : BigInt(delta);
  return n > 0n ? 'admin-adjust-preview pos' : 'admin-adjust-preview neg';
}

function formatSignedPreview(delta, suffix, isCents = false) {
  if (delta == null) return '—';
  const n = typeof delta === 'bigint' ? delta : BigInt(delta);
  const abs = n < 0n ? -n : n;
  const formatted = isCents ? formatCredits(abs.toString()) : formatUnits(abs);
  return `${n > 0n ? '+' : '−'}${formatted} ${suffix}`;
}

function AdjustRow({
  label,
  value,
  onChange,
  step = '1',
  delta,
  preview,
  result,
  onSubmit,
  busy,
}) {
  return (
    <form
      className="admin-adjust-row"
      onSubmit={(e) => {
        e.preventDefault();
        onSubmit();
      }}
    >
      <label>
        {label}
        <span className="admin-adjust-input-wrap">
          <input
            type="number"
            step={step}
            value={value}
            onChange={(e) => onChange(e.target.value)}
            required
          />
          <span className={previewClass(delta)}>{preview}</span>
        </span>
      </label>
      {result != null && <span className="admin-adjust-result muted">{result}</span>}
      <button className="btn" type="submit" disabled={busy || delta == null}>
        Apply
      </button>
    </form>
  );
}

export default function AdminPlayers() {
  const [users, setUsers] = useState([]);
  const [error, setError] = useState('');
  const [query, setQuery] = useState('');
  const [sort, setSort] = useState('wealth');
  const [adjustId, setAdjustId] = useState(null);
  const [deltaCredits, setDeltaCredits] = useState('100');
  const [deltaPr, setDeltaPr] = useState('1000');
  const [deltaOsu, setDeltaOsu] = useState('100');
  const [busy, setBusy] = useState(false);

  const deltaCents = useMemo(() => parseDeltaCents(deltaCredits), [deltaCredits]);
  const prDelta = useMemo(() => parseDeltaUnits(deltaPr), [deltaPr]);
  const osuDelta = useMemo(() => parseDeltaUnits(deltaOsu), [deltaOsu]);

  const load = useCallback(async () => {
    const data = await api.adminUsers();
    setUsers(data.users);
  }, []);

  useEffect(() => {
    load().catch((err) => setError(err.message));
  }, [load]);

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    let list = [...users];
    if (q) {
      list = list.filter((u) => u.username.toLowerCase().includes(q));
    }
    list.sort((a, b) => {
      if (sort === 'name') return a.username.localeCompare(b.username);
      if (sort === 'opens') return b.casesOpened - a.casesOpened;
      if (sort === 'recent') {
        return (
          new Date(b.lastConnection || 0).getTime() -
          new Date(a.lastConnection || 0).getTime()
        );
      }
      return compareCents(b.totalWealth, a.totalWealth);
    });
    return list;
  }, [users, query, sort]);

  const resetDeltas = () => {
    setDeltaCredits('100');
    setDeltaPr('1000');
    setDeltaOsu('100');
  };

  const applyPatch = async (userId, body) => {
    setBusy(true);
    setError('');
    try {
      await api.adminUpdateUser(userId, body);
      setAdjustId(null);
      resetDeltas();
      await load();
    } catch (err) {
      setError(err.message);
    } finally {
      setBusy(false);
    }
  };

  const applyCredits = async (userId) => {
    const cents = parseDeltaCents(deltaCredits);
    if (cents == null) {
      setError('Enter a non-zero credit amount (e.g. 100 or -50)');
      return;
    }
    await applyPatch(userId, { balanceDelta: cents });
  };

  const applyPr = async (userId) => {
    const delta = parseDeltaUnits(deltaPr);
    if (delta == null) {
      setError('Enter a non-zero Pr amount (e.g. 1000 or -100)');
      return;
    }
    await applyPatch(userId, { prBalanceDelta: delta.toString() });
  };

  const applyOsu = async (userId) => {
    const delta = parseDeltaUnits(deltaOsu);
    if (delta == null) {
      setError('Enter a non-zero osu amount (e.g. 100 or -50)');
      return;
    }
    // osuBalance is Int — stay within safe integer range for the JSON number API
    if (delta > BigInt(Number.MAX_SAFE_INTEGER) || delta < BigInt(Number.MIN_SAFE_INTEGER)) {
      setError('osu delta is too large');
      return;
    }
    await applyPatch(userId, { osuBalanceDelta: Number(delta) });
  };

  return (
    <div>
      <div className="section-head">
        <div>
          <h1>Players</h1>
          <p className="muted">{users.length} accounts · adjust credits, Pr & osu</p>
        </div>
        <div className="admin-toolbar">
          <select value={sort} onChange={(e) => setSort(e.target.value)} aria-label="Sort">
            <option value="wealth">Sort: wealth</option>
            <option value="opens">Sort: opens</option>
            <option value="recent">Sort: last seen</option>
            <option value="name">Sort: name</option>
          </select>
          <input
            className="admin-search"
            placeholder="Search players…"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
          />
        </div>
      </div>

      {error && <div className="error">{error}</div>}

      <div className="admin-card-list">
        {filtered.map((u) => (
          <div key={u.id} className="admin-block admin-player-card">
            <div className="admin-row">
              <div className="admin-thumb">
                {u.avatarUrl ? (
                  <img src={u.avatarUrl} alt="" />
                ) : (
                  <span>{u.username.slice(0, 2).toUpperCase()}</span>
                )}
              </div>
              <div className="admin-row-main">
                <strong>@{u.username}</strong>
                <div className="muted">
                  Wealth {formatCredits(u.totalWealth)} cr · bal{' '}
                  {formatCredits(u.balance)} · inv {formatCredits(u.inventoryValue)} (
                  {u.inventoryCount})
                </div>
                <div className="muted">
                  {formatUnits(u.prBalance ?? 0)} Pr · {formatUnits(u.osuBalance ?? 0)} osu · opens{' '}
                  {u.casesOpened} · prestige {u.prestigeCount} · achievements {u.achievements} · play{' '}
                  {formatPlayTime(u.playTimeSeconds)} · last{' '}
                  {formatLastConnection(u.lastConnection)}
                </div>
              </div>
              <button
                type="button"
                className="btn secondary"
                onClick={() => {
                  setAdjustId(adjustId === u.id ? null : u.id);
                  resetDeltas();
                }}
              >
                Adjust
              </button>
            </div>
            {adjustId === u.id && (
              <div className="admin-adjust-panel">
                <AdjustRow
                  label="Δ credits (e.g. 100 or -50)"
                  value={deltaCredits}
                  onChange={setDeltaCredits}
                  step="0.01"
                  delta={deltaCents == null ? null : BigInt(deltaCents)}
                  preview={formatSignedPreview(
                    deltaCents == null ? null : BigInt(deltaCents),
                    'cr',
                    true
                  )}
                  result={
                    deltaCents == null
                      ? null
                      : `→ bal ${formatCredits(balanceAfterDelta(u.balance, deltaCents))} cr`
                  }
                  onSubmit={() => applyCredits(u.id)}
                  busy={busy}
                />
                <AdjustRow
                  label="Δ Pr (e.g. 1000 or -100)"
                  value={deltaPr}
                  onChange={setDeltaPr}
                  delta={prDelta}
                  preview={formatSignedPreview(prDelta, 'Pr')}
                  result={
                    prDelta == null
                      ? null
                      : `→ ${formatUnits(balanceAfterDelta(u.prBalance ?? 0, prDelta))} Pr`
                  }
                  onSubmit={() => applyPr(u.id)}
                  busy={busy}
                />
                <AdjustRow
                  label="Δ osu (e.g. 100 or -50)"
                  value={deltaOsu}
                  onChange={setDeltaOsu}
                  delta={osuDelta}
                  preview={formatSignedPreview(osuDelta, 'osu')}
                  result={
                    osuDelta == null
                      ? null
                      : `→ ${formatUnits(balanceAfterDelta(u.osuBalance ?? 0, osuDelta))} osu`
                  }
                  onSubmit={() => applyOsu(u.id)}
                  busy={busy}
                />
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
