/* ── Shared chat panel ───────────────────────────────────────────────────── */
function ChatPanel({ messages, onSend, title }) {
  const { useState, useEffect, useRef } = React;
  const [input, setInput] = useState('');
  const endRef = useRef(null);

  useEffect(() => {
    endRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages.length]);

  function handleSubmit(e) {
    e.preventDefault();
    const msg = input.trim();
    if (!msg) return;
    onSend(msg);
    setInput('');
  }

  return (
    <div className="poker-chat-panel">
      {title && <h3 className="poker-section-title">{title}</h3>}
      <div className="poker-chat-messages">
        {messages.length === 0 && <p className="poker-chat-empty">No messages yet</p>}
        {messages.map((m, i) => (
          <div key={i} className="poker-chat-msg">
            <span className="poker-chat-user">{m.username}</span>
            <span className="poker-chat-text">{m.message}</span>
          </div>
        ))}
        <div ref={endRef} />
      </div>
      <form className="poker-chat-form" onSubmit={handleSubmit}>
        <input
          className="poker-input poker-chat-input"
          value={input}
          onChange={e => setInput(e.target.value)}
          placeholder="Say something…"
          maxLength={200}
        />
        <button className="btn btn-primary btn-sm" type="submit">Send</button>
      </form>
    </div>
  );
}

/* ── Group Poker (Texas Hold'em) ─────────────────────────────────────────── */
function jwtUsername(token) {
  try { return JSON.parse(atob(token.split('.')[1])).username; } catch { return ''; }
}

function Poker({ balance, token, onBack, onBalanceChange }) {
  const { useState, useEffect, useRef, useCallback } = React;

  const username = jwtUsername(token);

  const [phase,        setPhase]        = useState('lobby');   // lobby | seat | table
  const [tables,       setTables]       = useState([]);
  const [table,        setTable]        = useState(null);
  const [err,          setErr]          = useState('');
  const [buyin,        setBuyin]        = useState(1000);
  const [stakes,       setStakes]       = useState({ small: 25, big: 50 });
  const [tname,        setTname]        = useState('');
  const [tpassword,    setTpassword]    = useState('');      // password for table being created
  const [joiningTable, setJoiningTable] = useState(null);   // { id, name, hasPassword }
  const [joinPassword, setJoinPassword] = useState('');
  const [chatMessages,      setChatMessages]      = useState([]);  // lobby
  const [tableChatMessages, setTableChatMessages] = useState([]);  // table

  const socketRef       = useRef(null);
  const isSpectatingRef = useRef(false);

  useEffect(() => {
    if (window.io) {
      connectSocket();
    } else {
      const s = document.createElement('script');
      s.src = '/socket.io/socket.io.js';
      s.onload = connectSocket;
      document.head.appendChild(s);
    }
    return () => { if (socketRef.current) socketRef.current.disconnect(); };
  }, []);

  function connectSocket() {
    const sock = window.io({ auth: { token } });
    socketRef.current = sock;

    sock.on('poker:list',  setTables);
    sock.on('poker:table', (t) => { setTable(t); setPhase(isSpectatingRef.current ? 'spectate' : 'table'); });
    sock.on('poker:joined', ({ balance: bal }) => { onBalanceChange && onBalanceChange(bal); });
    sock.on('poker:left',  ({ balance: bal }) => {
      isSpectatingRef.current = false;
      if (bal != null) onBalanceChange && onBalanceChange(bal);
      setPhase('lobby');
      setTable(null);
      setTableChatMessages([]);
    });
    sock.on('poker:closed', ({ balance: bal }) => {
      isSpectatingRef.current = false;
      if (bal != null) onBalanceChange && onBalanceChange(bal);
      setPhase('lobby');
      setTable(null);
      setTableChatMessages([]);
      setErr('This table was closed by an admin. Your balance has been refunded.');
    });
    sock.on('poker:error',      (msg) => setErr(msg));
    sock.on('poker:lobby-chat', (msg) => setChatMessages(ms => [...ms.slice(-99), msg]));
    sock.on('poker:chat',       (msg) => setTableChatMessages(ms => [...ms.slice(-99), msg]));
  }

  const emit = useCallback((ev, data) => {
    setErr('');
    socketRef.current?.emit(ev, data);
  }, []);

  const sendChat = useCallback((msg) => {
    socketRef.current?.emit('poker:chat', { message: msg });
  }, []);

  function spectate(t) {
    isSpectatingRef.current = true;
    emit('poker:spectate', { tableId: t.id });
  }

  function stopSpectating() {
    isSpectatingRef.current = false;
    emit('poker:unspectate');
  }

  // ── Lobby ──────────────────────────────────────────────────────────────────
  if (phase === 'lobby') return (
    <div className="game-panel game-panel--wide" data-game-view="poker">
      <div className="game-panel-header">
        <button className="btn-back" onClick={onBack}>Lobby</button>
        <div>
          <h1 className="game-panel-title">Group Poker</h1>
          <div className="game-panel-subtitle">·❦· The Long Game ·❦·</div>
        </div>
        <div className="game-panel-meta"><span>2–8 Seats</span></div>
      </div>

      <div className="poker-lobby">
        <div className="poker-lobby-create">
          <h3 className="poker-section-title">Create Table</h3>
          <div className="poker-form-row">
            <label>Table Name</label>
            <input className="poker-input" value={tname} onChange={e=>setTname(e.target.value)} placeholder="My Table" maxLength={24} />
          </div>
          <div className="poker-form-row">
            <label>Buy-in (G)</label>
            <input className="poker-input" type="number" value={buyin} onChange={e=>setBuyin(parseInt(e.target.value)||0)} min={100} step={100} />
          </div>
          <div className="poker-form-row">
            <label>Blinds</label>
            <select className="poker-input" value={`${stakes.small}/${stakes.big}`} onChange={e=>{const[s,b]=e.target.value.split('/');setStakes({small:+s,big:+b});}}>
              <option value="10/20">10 / 20</option>
              <option value="25/50">25 / 50</option>
              <option value="50/100">50 / 100</option>
              <option value="100/200">100 / 200</option>
              <option value="250/500">250 / 500</option>
            </select>
          </div>
          <div className="poker-form-row">
            <label>Password (optional)</label>
            <input className="poker-input" type="password" value={tpassword} onChange={e=>setTpassword(e.target.value)} placeholder="Leave blank for public" maxLength={32} />
          </div>
          <button className="btn btn-primary" onClick={() => { window.SoundFX?.chip(); emit('poker:create', { name: tname||undefined, stakes, buyin, password: tpassword||undefined }); }}>
            Create &amp; Join
          </button>
        </div>

        <div className="poker-lobby-tables">
          <h3 className="poker-section-title">Open Tables</h3>
          {tables.length === 0 && <p className="poker-empty">No tables yet — create one above</p>}
          {tables.map(t => (
            <div key={t.id} className="poker-table-row">
              <div className="poker-table-info">
                <span className="poker-table-name">
                  {t.hasPassword ? <span className="poker-lock" title="Password protected">🔒</span> : null}
                  {t.name}
                </span>
                <span className="poker-table-meta">{t.stakes.small}/{t.stakes.big} blinds · {t.seats} seated · {t.phase}</span>
              </div>
              <div style={{ display: 'flex', gap: 6 }}>
                <button className="btn btn-primary btn-sm"
                  onClick={() => { window.SoundFX?.chip(); setJoiningTable(t); setJoinPassword(''); setPhase('seat'); }}>
                  Join
                </button>
                <button className="btn btn-sm" onClick={() => spectate(t)}>
                  Spectate
                </button>
              </div>
            </div>
          ))}
        </div>

        <ChatPanel messages={chatMessages} onSend={sendChat} title="Lobby Chat" />
      </div>
      {err && <p className="poker-err">{err}</p>}
    </div>
  );

  // ── Buy-in screen ──────────────────────────────────────────────────────────
  if (phase === 'seat') return (
    <div className="game-panel" data-game-view="poker">
      <div className="game-panel-header">
        <button className="btn-back" onClick={() => setPhase('lobby')}>Back</button>
        <div>
          <h1 className="game-panel-title">Join — {joiningTable?.name}</h1>
          <div className="game-panel-subtitle">·❦· Buy In ·❦·</div>
        </div>
        <div className="game-panel-meta"><span>Hold'em</span></div>
      </div>
      <div style={{ padding: '32px 0', maxWidth: 320, margin: '0 auto' }}>
        <div className="poker-form-row">
          <label>Buy-in (G)</label>
          <input className="poker-input" type="number" value={buyin} onChange={e=>setBuyin(parseInt(e.target.value)||0)} min={100} step={100} />
        </div>
        {joiningTable?.hasPassword && (
          <div className="poker-form-row">
            <label>🔒 Password</label>
            <input className="poker-input" type="password" value={joinPassword} onChange={e=>setJoinPassword(e.target.value)} placeholder="Enter table password" maxLength={32} />
          </div>
        )}
        <p style={{ color: 'var(--muted)', fontSize: 13, marginBottom: 16 }}>Balance: {balance.toLocaleString()} G</p>
        <button className="btn btn-primary btn-lg" onClick={() => { window.SoundFX?.chip(); emit('poker:join', { tableId: joiningTable.id, buyin, password: joinPassword||undefined }); }}>
          Sit Down
        </button>
      </div>
      {err && <p className="poker-err">{err}</p>}
    </div>
  );

  // ── Spectate view ──────────────────────────────────────────────────────────
  if (phase === 'spectate' && table) return (
    <PokerTable table={table} username={username}
      onAction={() => {}} onStart={() => {}} onLeave={stopSpectating}
      chatMessages={tableChatMessages} onChat={sendChat}
      err={err} spectating={true}
    />
  );

  // ── Table view ─────────────────────────────────────────────────────────────
  if (phase === 'table' && table) return (
    <PokerTable table={table} username={username}
      onAction={(a,amt) => emit('poker:action', { action: a, amount: amt })}
      onStart={() => emit('poker:start')}
      onLeave={() => emit('poker:leave')}
      onSitOut={() => emit('poker:sitout')}
      onRebuy={() => emit('poker:rebuy')}
      chatMessages={tableChatMessages}
      onChat={sendChat}
      err={err}
    />
  );

  return <div className="game-panel"><p style={{padding:40,color:'var(--muted)'}}>Connecting…</p></div>;
}

// ── Poker card helpers (module-level so the function reference is stable) ──────
function _pokerCardLabel(c) {
  if (c.hidden) return { rank: '?', suit: '?', red: false };
  return { rank: c.rank, suit: c.suit, red: c.suit === '♥' || c.suit === '♦' };
}

function PokerCard({ card, big, dealDelay }) {
  const { rank, suit, red } = _pokerCardLabel(card);
  const animStyle = dealDelay !== undefined
    ? { animation: `pcardDeal 0.32s cubic-bezier(0.2,0.8,0.3,1) ${dealDelay}ms both` }
    : {};
  return (
    <div
      className={`pcard${big ? ' pcard--big' : ''}${card.hidden ? ' pcard--hidden' : ''}`}
      style={{ color: red ? 'var(--garnet)' : '#1a1a1a', ...animStyle }}
    >
      {!card.hidden && <>
        <div className="pcard-rank">{rank}</div>
        <div className="pcard-suit">{suit}</div>
      </>}
    </div>
  );
}

// ── Poker Table Component ──────────────────────────────────────────────────────
function PokerTable({ table, username, onAction, onStart, onLeave, onSitOut, onRebuy, chatMessages, onChat, err, spectating = false }) {
  const { useState, useEffect, useRef } = React;
  const [raiseAmt, setRaiseAmt] = useState('');
  const [secsLeft, setSecsLeft] = useState(null);
  const timerTickRef = useRef(null);

  // Animation state
  const [handKey,        setHandKey]        = useState(0);   // bumps on each new deal
  const [visibleCommCount, setVisibleCommCount] = useState(0); // community cards revealed so far
  const prevPhaseRef   = useRef(table.phase);
  const prevCommLenRef = useRef(0);
  const timersRef      = useRef([]);

  // Detect new hand — reset community counter, bump handKey so hole cards remount
  useEffect(() => {
    const prev = prevPhaseRef.current;
    prevPhaseRef.current = table.phase;
    if (table.phase === 'preflop' && prev !== 'preflop') {
      timersRef.current.forEach(clearTimeout);
      timersRef.current = [];
      prevCommLenRef.current = 0;
      setVisibleCommCount(0);
      setHandKey(k => k + 1);
    }
    if (table.phase === 'waiting') {
      setVisibleCommCount(0);
      prevCommLenRef.current = 0;
    }
  }, [table.phase]);

  // Stagger community card reveals (flop = 3 cards 350 ms apart, turn/river = 1)
  useEffect(() => {
    const prev = prevCommLenRef.current;
    const curr = table.community.length;
    if (curr <= prev) return;
    prevCommLenRef.current = curr;
    timersRef.current.forEach(clearTimeout);
    timersRef.current = [];
    for (let i = prev; i < curr; i++) {
      const t = setTimeout(() => setVisibleCommCount(i + 1), (i - prev) * 350 + 120);
      timersRef.current.push(t);
    }
  }, [table.community.length]);

  useEffect(() => () => timersRef.current.forEach(clearTimeout), []);

  // Countdown for the acting player's 45-second window
  useEffect(() => {
    if (timerTickRef.current) { clearInterval(timerTickRef.current); timerTickRef.current = null; }
    if (!table.actingDeadline) { setSecsLeft(null); return; }
    const tick = () => setSecsLeft(Math.max(0, Math.ceil((table.actingDeadline - Date.now()) / 1000)));
    tick();
    timerTickRef.current = setInterval(tick, 500);
    return () => { clearInterval(timerTickRef.current); timerTickRef.current = null; };
  }, [table.actingDeadline]);

  const myIdx  = table.seats.findIndex(s => s.username === username);
  const mySeat = myIdx >= 0 ? table.seats[myIdx] : null;
  const isMyTurn = myIdx === table.actingIdx;
  const canCheck = isMyTurn && mySeat && (mySeat.bet >= table.currentBet);

  return (
    <div className="game-panel game-panel--wide" data-game-view="poker">
      <div className="game-panel-header">
        <button className="btn-back" onClick={onLeave}>{spectating ? 'Stop Watching' : 'Leave'}</button>
        <div>
          <h1 className="game-panel-title">{table.name}</h1>
          <div className="game-panel-subtitle">·❦· Texas Hold'em ·❦·</div>
        </div>
        <div className="game-panel-meta">
          {spectating
            ? <span className="poker-phase-badge" style={{ background: 'rgba(212,169,96,0.15)', color: 'var(--gold)' }}>Spectating</span>
            : <span className="poker-phase-badge">{table.phase}</span>}
        </div>
      </div>

      <div className="poker-table-layout">
        {/* Left — chat */}
        <div className="poker-chat-col">
          <ChatPanel messages={chatMessages} onSend={onChat} title="Table Chat" />
        </div>

        {/* Right — game */}
        <div className="poker-game-col">
          {/* Community cards + pot */}
          <div className="poker-felt">
            {table.sidePots && table.sidePots.length > 1 ? (
              <div className="poker-pot poker-pot--split">
                {table.sidePots.map((p, i) => (
                  <span key={i} className="poker-pot-item">
                    {i === 0 ? 'Main' : `Side ${i}`}: {p.amount.toLocaleString()} G
                  </span>
                ))}
              </div>
            ) : (
              <div className="poker-pot">Pot: {table.pot.toLocaleString()} G</div>
            )}
            <div className="poker-community">
              {visibleCommCount === 0 && <span className="poker-community-empty">Waiting for cards…</span>}
              {table.community.slice(0, visibleCommCount).map((c,i) => (
                <PokerCard key={i} card={c} big dealDelay={0} />
              ))}
            </div>
          </div>

          {/* Seats */}
          <div className="poker-seats">
            {table.seats.map((seat, i) => {
              const isDealer = i === table.dealerIdx;
              const isActor  = i === table.actingIdx;
              const isMe     = seat.username === username;
              return (
                <div key={i} className={`poker-seat${isActor?' poker-seat--active':''}${seat.folded&&!seat.sitout?' poker-seat--folded':''}${seat.sitout?' poker-seat--sitout':''}${isMe?' poker-seat--me':''}${seat.winner?' poker-seat--winner':''}`}>
                  <div className="poker-seat-header">
                    <span className="poker-seat-name">{seat.username}{isDealer?' 🅓':''}</span>
                    <span className="poker-seat-chips">{seat.chips.toLocaleString()} G</span>
                  </div>
                  <div className="poker-seat-cards">
                    {seat.cards.length > 0
                      ? seat.cards.map((c,ci) => (
                          <PokerCard
                            key={`${handKey}-${ci}`}
                            card={c}
                            dealDelay={(i * 2 + ci) * 110}
                          />
                        ))
                      : <div className="poker-seat-nocard" />}
                  </div>
                  {seat.sitout && <div className="poker-seat-sitout">Sitting Out</div>}
                  {seat.bet > 0 && !seat.sitout && <div className="poker-seat-bet">Bet: {seat.bet.toLocaleString()}</div>}
                  {isActor && secsLeft !== null && (
                    <div className="poker-turn-bar-wrap">
                      <div className="poker-turn-bar" style={{
                        width: `${Math.max(0, (secsLeft / 45) * 100)}%`,
                        background: secsLeft <= 10 ? 'var(--garnet)' : 'var(--gold)',
                      }} />
                    </div>
                  )}
                  {seat.allin && <div className="poker-seat-allin">ALL IN</div>}
                  {table.phase === 'showdown' && seat.handName && (
                    <div className="poker-seat-handname" style={seat.folded ? { opacity: 0.45 } : {}}>
                      {seat.handName}{seat.winner ? ' ✦' : ''}
                    </div>
                  )}
                </div>
              );
            })}
          </div>

          {/* My hole cards */}
          {mySeat && mySeat.cards.length > 0 && (
            <div className="poker-myhand">
              <span className="poker-myhand-label">Your Hand</span>
              {mySeat.cards.map((c,i) => (
                <PokerCard
                  key={`${handKey}-my-${i}`}
                  card={c}
                  big
                  dealDelay={myIdx * 2 * 110 + i * 110 + 80}
                />
              ))}
            </div>
          )}

          {/* Actions */}
          {spectating ? (
            <div className="bet-controls" style={{ justifyContent: 'center' }}>
              <p style={{ color: 'var(--muted)', fontSize: 13, fontStyle: 'italic', fontFamily: 'Cormorant Garamond, serif' }}>
                Watching — bets and actions are disabled
              </p>
            </div>
          ) : (
            <div className="bet-controls" style={{ gap: 8, flexWrap: 'wrap' }}>
              {mySeat && (
                <button
                  className={`btn${mySeat.sitout ? ' btn-primary' : ''}`}
                  onClick={() => { window.SoundFX?.chip(); onSitOut(); }}
                  style={{ minWidth: 110 }}
                >
                  {mySeat.sitout ? 'Return' : 'Sit Out'}
                </button>
              )}
              {table.phase === 'waiting' && (
                <button className="btn btn-primary btn-lg" onClick={() => { window.SoundFX?.chip(); onStart(); }}>Start Hand</button>
              )}
              {isMyTurn && table.phase !== 'waiting' && table.phase !== 'showdown' && (
                <>
                  {secsLeft !== null && (
                    <div style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                      <div style={{ flex: 1, height: 3, background: 'rgba(255,255,255,0.08)', borderRadius: 2, overflow: 'hidden' }}>
                        <div style={{ height: '100%', borderRadius: 2, transition: 'width 0.5s linear, background 0.3s', width: `${Math.max(0, (secsLeft / 45) * 100)}%`, background: secsLeft <= 10 ? 'var(--garnet)' : 'var(--gold)' }} />
                      </div>
                      <span style={{ fontSize: 11, color: secsLeft <= 10 ? 'var(--garnet)' : 'var(--muted)', fontFamily: 'JetBrains Mono, monospace', minWidth: 28, textAlign: 'right' }}>{secsLeft}s</span>
                    </div>
                  )}
                  <button className="btn" onClick={() => { window.SoundFX?.chip(); onAction('fold'); }}>Fold</button>
                  {canCheck
                    ? <button className="btn btn-primary" onClick={() => { window.SoundFX?.chip(); onAction('check'); }}>Check</button>
                    : <button className="btn btn-primary" onClick={() => { window.SoundFX?.chip(); onAction('call'); }}>
                        Call {Math.min(table.currentBet - (mySeat.bet||0), mySeat.chips).toLocaleString()}
                      </button>
                  }
                  <div style={{ display:'flex', gap:4 }}>
                    <input
                      className="poker-input" type="number" placeholder="Raise to…"
                      value={raiseAmt} onChange={e=>setRaiseAmt(e.target.value)}
                      style={{ width:110 }}
                    />
                    <button className="btn" onClick={() => { window.SoundFX?.chip(); onAction('raise', raiseAmt); setRaiseAmt(''); }}>Raise</button>
                  </div>
                  <button className="btn" onClick={() => { window.SoundFX?.chip(); onAction('allin'); }}>All In</button>
                </>
              )}
              {!isMyTurn && table.phase !== 'waiting' && table.phase !== 'showdown' && (
                <p style={{ color:'var(--muted)', fontSize:13 }}>
                  Waiting for {table.seats[table.actingIdx]?.username}…
                  {secsLeft !== null && (
                    <span style={{ marginLeft: 8, color: secsLeft <= 10 ? 'var(--garnet)' : 'var(--muted)', fontFamily: 'JetBrains Mono, monospace' }}>
                      {secsLeft}s
                    </span>
                  )}
                </p>
              )}
            </div>
          )}
          {err && <p className="poker-err">{err}</p>}
        </div>
      </div>

      {/* Rebuy modal — shown when seated player runs out of chips */}
      {!spectating && mySeat && mySeat.chips === 0 && table.phase === 'waiting' && (
        <div className="poker-rebuy-overlay">
          <div className="poker-rebuy-modal">
            <h2 className="poker-rebuy-title">Out of Chips</h2>
            <p className="poker-rebuy-body">
              Buy back in for <strong>{table.buyin?.toLocaleString()} G</strong> to keep playing.
            </p>
            <div className="poker-rebuy-actions">
              <button
                className="btn btn-primary btn-lg"
                onClick={() => { window.SoundFX?.chip(); onRebuy && onRebuy(); }}
              >
                Buy Back In — {table.buyin?.toLocaleString()} G
              </button>
              <button className="btn btn-lg" onClick={onLeave}>Leave Table</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
