import { useCallback, useEffect, useMemo, useState } from 'react';
import { Link, Navigate, useNavigate, useParams } from 'react-router-dom';
import { api, formatCredits, formatChance, compareCents } from '../api';
import { useAuth } from '../AuthContext';
import ItemTile, { itemValueCents } from '../components/ItemTile';
import CaseReel from '../components/CaseReel';
import { useCountdown } from '../hooks/useCountdown';
import { onInventoryChanged } from '../inventoryEvents';
import { getSocket } from '../socket';

/**
 * Create mode (`/battle/create`) or join/spectate (`/battle/:id`).
 */
export default function BattleRoomPage({ create = false }) {
  const { id: paramId } = useParams();
  const battleId = create ? null : Number(paramId);
  const navigate = useNavigate();
  const { user, loading, refresh } = useAuth();
  const [round, setRound] = useState(null);
  const [inventory, setInventory] = useState([]);
  const [selected, setSelected] = useState([]);
  const [error, setError] = useState('');
  const [busy, setBusy] = useState(false);
  const [spinning, setSpinning] = useState(false);
  const [reelWinnerItemId, setReelWinnerItemId] = useState(null);
  const [lastWinner, setLastWinner] = useState(null);
  const [revealWinner, setRevealWinner] = useState(false);
  const [spinDeposits, setSpinDeposits] = useState([]);
  const [spinActive, setSpinActive] = useState(false);

  const { label: timerLabel, remaining } = useCountdown(
    round?.status === 'open' && round?.endsAt && !round?.waitingForPlayers
      ? round.endsAt
      : null
  );

  const loadInventory = useCallback(async () => {
    const inv = await api.inventory();
    setInventory(inv.inventory);
  }, []);

  const inventoryByValue = useMemo(
    () =>
      [...inventory].sort(
        (a, b) =>
          compareCents(itemValueCents(b.item), itemValueCents(a.item)) ||
          compareCents(b.valueCents, a.valueCents)
      ),
    [inventory]
  );

  useEffect(() => {
    if (!user || user.role === 'admin') return undefined;
    let cancelled = false;

    (async () => {
      try {
        await loadInventory();
        if (create) {
          if (!cancelled) setRound(null);
          return;
        }
        if (!battleId) {
          if (!cancelled) setError('Invalid battle');
          return;
        }
        const data = await api.jackpotRound(battleId);
        if (cancelled) return;
        setRound(data.round);
        if (data.round?.status === 'spinning') {
          setSpinDeposits(data.round.deposits || []);
          setSpinActive(true);
          setSpinning(true);
          setLastWinner(data.round.winnerUsername || null);
        }
        if (data.round?.status === 'resolved' || data.round?.status === 'cancelled') {
          setLastWinner(data.round.winnerUsername || null);
          if (data.round.status === 'resolved') setRevealWinner(true);
        }
      } catch (err) {
        if (!cancelled) setError(err.message);
      }
    })();

    if (create || !battleId) {
      return () => {
        cancelled = true;
      };
    }

    const socket = getSocket();
    const onState = (state) => {
      if (state?.id && state.id !== battleId) return;
      setRound(state);
      if (state?.status === 'cancelled') {
        navigate('/battle', { replace: true });
        return;
      }
      if (state?.status === 'open') {
        loadInventory().catch(() => {});
      }
    };
    const onSpin = (state) => {
      if (state?.id && state.id !== battleId) return;
      setRound(state);
      setSpinDeposits(state.deposits || []);
      setSpinActive(true);
      setSpinning(true);
      setRevealWinner(false);
      setReelWinnerItemId(state.reelWinnerItemId);
      setLastWinner(state.winnerUsername);
    };
    const onResult = (state) => {
      if (state?.previousRoundId && state.previousRoundId !== battleId) return;
      if (state?.id && state.id !== battleId && !state.previousRoundId) return;
      setRound(state);
      if (state.winnerUsername) setLastWinner(state.winnerUsername);
      setRevealWinner(true);
      setSpinning(false);
      loadInventory().catch(() => {});
      refresh().catch(() => {});
    };

    socket.emit('jackpot:subscribe', battleId);
    socket.on('jackpot:state', onState);
    socket.on('jackpot:spin', onSpin);
    socket.on('jackpot:result', onResult);
    socket.on('connect', () => socket.emit('jackpot:subscribe', battleId));

    return () => {
      cancelled = true;
      socket.emit('jackpot:unsubscribe', battleId);
      socket.off('jackpot:state', onState);
      socket.off('jackpot:spin', onSpin);
      socket.off('jackpot:result', onResult);
    };
  }, [user, create, battleId, loadInventory, refresh, navigate]);

  useEffect(() => {
    if (!user || user.role === 'admin') return undefined;
    return onInventoryChanged(() => {
      loadInventory().catch(() => {});
      refresh().catch(() => {});
    });
  }, [user, loadInventory, refresh]);

  const maxItems = round?.maxItemsPerPlayer || 3;
  const myDeposits = useMemo(
    () => (round?.deposits || []).filter((d) => d.userId === user?.id),
    [round, user]
  );
  const mySlotsLeft = Math.max(0, maxItems - myDeposits.length);
  const canBet =
    create || round?.status === 'open' || (!round && create);

  const potItems = useMemo(() => {
    const source = spinActive && spinDeposits.length ? spinDeposits : round?.deposits || [];
    return source
      .filter((d) => d.item)
      .map((d) => ({
        ...d.item,
        id: d.id,
        ownerUsername: d.username,
        ownerAvatarUrl: d.avatarUrl || '',
      }));
  }, [round, spinDeposits, spinActive]);

  const showReel = spinActive && potItems.length > 0;

  useEffect(() => {
    if (!revealWinner) return undefined;
    const t = setTimeout(() => setSpinActive(false), 5000);
    return () => clearTimeout(t);
  }, [revealWinner]);

  const toggleSelect = (invId) => {
    setSelected((prev) => {
      if (prev.includes(invId)) return prev.filter((id) => id !== invId);
      if (prev.length >= mySlotsLeft) return prev;
      return [...prev, invId];
    });
  };

  const placeBet = async () => {
    if (!selected.length) return;
    setBusy(true);
    setError('');
    try {
      if (create && !round) {
        const data = await api.jackpotCreateBet(selected);
        setSelected([]);
        await loadInventory();
        navigate(`/battle/${data.round.id}`, { replace: true });
        return;
      }
      const data = await api.jackpotBet(round.id, selected);
      setRound(data.round);
      setSelected([]);
      await loadInventory();
    } catch (err) {
      setError(err.message);
    } finally {
      setBusy(false);
    }
  };

  const withdraw = async (inventoryItemIds) => {
    if (!round?.id) return;
    setBusy(true);
    setError('');
    try {
      const data = await api.jackpotWithdraw(round.id, inventoryItemIds);
      if (data.round?.status === 'cancelled') {
        navigate('/battle', { replace: true });
        return;
      }
      setRound(data.round);
      await loadInventory();
    } catch (err) {
      setError(err.message);
    } finally {
      setBusy(false);
    }
  };

  if (loading) return <p className="muted">Loading…</p>;
  if (!user) return <Navigate to="/login" replace />;
  if (user.role === 'admin') return <Navigate to="/admin" replace />;

  const title = create && !round ? 'Create a Battle' : round?.name || `Battle ${battleId || ''}`;
  const isOpen = create || round?.status === 'open';

  return (
    <div className="bet-page">
      <div className="section-head">
        <div>
          <h1>{title}</h1>
          <p className="muted">
            {create && !round
              ? 'Bet items to open a new battle. Chance = your value / total pot.'
              : 'Win chance = your value / total pot.'}
          </p>
        </div>
        <Link to="/battle" className="btn secondary">
          Back
        </Link>
      </div>

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

      <div className="jackpot-status">
        <div className="timer-block">
          <span className="muted">Battle</span>
          <strong>#{round?.id || '—'}</strong>
          <span className={`status-pill ${round?.status || ''}`}>
            {round?.status || (create ? 'new' : '…')}
          </span>
        </div>
        <div className="timer-block">
          <span className="muted">Timer</span>
          <strong className="timer-digits">
            {round?.status === 'spinning' || spinning
              ? 'SPIN'
              : round?.waitingForPlayers || (create && !round)
                ? 'WAIT'
                : round?.status === 'open' && round?.endsAt
                  ? timerLabel
                  : '—'}
          </strong>
          {((round?.waitingForPlayers && round?.status === 'open') || (create && !round)) && (
            <span className="muted">
              Need {round?.minPlayers || 2} players ({round?.players?.length || 0}/
              {round?.minPlayers || 2})
            </span>
          )}
          {round?.status === 'open' &&
            !round?.waitingForPlayers &&
            remaining <= 5 &&
            remaining > 0 && <span className="muted">closing…</span>}
        </div>
        <div className="timer-block">
          <span className="muted">Pot</span>
          <strong className="gold">{formatCredits(round?.totalValue || 0)} cr</strong>
        </div>
      </div>

      {showReel && (
        <div className="section">
          <CaseReel
            items={potItems}
            winnerId={reelWinnerItemId || potItems[0]?.id}
            spinning={spinning || round?.status === 'spinning'}
            showOwners
            onDone={() => {
              setSpinning(false);
              setRevealWinner(true);
            }}
          />
          {revealWinner && lastWinner && (
            <div className="won-banner" style={{ marginTop: '0.75rem' }}>
              Winner: <strong>{lastWinner}</strong>
            </div>
          )}
        </div>
      )}
      {!showReel && revealWinner && lastWinner && (
        <div className="won-banner section">
          Winner: <strong>{lastWinner}</strong>
        </div>
      )}

      <section className="section">
        <h2>Players</h2>
        {(round?.players || []).length === 0 ? (
          <div className="empty">No bets yet — be the first.</div>
        ) : (
          <table className="table">
            <thead>
              <tr>
                <th>Player</th>
                <th>Value</th>
                <th>Items</th>
                <th>Chance</th>
              </tr>
            </thead>
            <tbody>
              {round.players.map((p) => (
                <tr key={p.userId} className={p.userId === user.id ? 'row-me' : ''}>
                  <td>{p.username}</td>
                  <td>{formatCredits(p.valueCents)} cr</td>
                  <td>{p.itemCount}</td>
                  <td>{formatChance(p.chance)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </section>

      <section className="section">
        <h2>Pot items</h2>
        {(round?.deposits || []).length === 0 ? (
          <div className="empty">Empty pot.</div>
        ) : (
          <div className="grid">
            {round.deposits.map((d) => (
              <div key={d.id} className="deposit-wrap">
                <ItemTile item={d.item} />
                <div className="deposit-owner muted">{d.username}</div>
              </div>
            ))}
          </div>
        )}
      </section>

      {myDeposits.length > 0 && round?.status === 'open' && (
        <section className="section">
          <div className="section-head">
            <h2>
              Your bets ({myDeposits.length}/{maxItems})
            </h2>
            <button
              type="button"
              className="btn danger"
              disabled={busy}
              onClick={() => withdraw(myDeposits.map((d) => d.inventoryItemId))}
            >
              Withdraw all
            </button>
          </div>
        </section>
      )}

      {isOpen && canBet && (
        <section className="section">
          <div className="section-head">
            <div>
              <h2>{create && !round ? 'Bet to create' : 'Bet from inventory'}</h2>
              <p className="muted">
                Select up to {mySlotsLeft} more item{mySlotsLeft === 1 ? '' : 's'}.
              </p>
            </div>
            <button
              type="button"
              className="btn"
              disabled={busy || !selected.length || mySlotsLeft === 0}
              onClick={placeBet}
            >
              {create && !round ? 'Create battle' : 'Place bet'}
            </button>
          </div>
          {inventoryByValue.length === 0 ? (
            <div className="empty">
              No free items — <Link to="/cases">open a case</Link>.
            </div>
          ) : (
            <div className="grid">
              {inventoryByValue.map((inv) => (
                <ItemTile
                  key={inv.id}
                  item={inv.item}
                  favorite={inv.favorite}
                  staked={inv.staked}
                  selected={selected.includes(inv.id)}
                  disabled={
                    inv.staked ||
                    (mySlotsLeft === 0 && !selected.includes(inv.id))
                  }
                  onClick={() => toggleSelect(inv.id)}
                />
              ))}
            </div>
          )}
        </section>
      )}
    </div>
  );
}
