import * as bus from '../../../core/bus.js';
import * as scene from '../../../core/scene.js';
import * as store from '../../../core/store.js';
import * as net from '../../../core/net.js';
import * as audio from '../../../core/audio.js';
import { t } from '../../../core/i18n.js';
import { ChessBoard } from '../canvas/board.js';
import * as engine from '../logic/engine.js';
import { ChessClock, parseTimeControl } from '../logic/clock.js';
import * as juice from '../../../core/juice.js';
import { getOpeningName } from '../logic/openings.js';
import { getMaterialAdvantage, formatAdvantage } from '../logic/material.js';
import * as emoteSystem from '../components/emotes.js';
import * as mp from '../../../core/multiplayer.js';
import { emoji } from '../../../core/theme.js';

let board, clock, gameState;

export function mountGame(el, params) {
  const { mode = 'bot', botId = 'amina', timeControl = 'rapid_10_0', matchId, color } = params;
  const playerColor = color || 'w';
  const tc = parseTimeControl(timeControl);

  scene.enterGameMode();

  gameState = {
    mode, botId, matchId, playerColor, timeControl,
    isPlayerTurn: playerColor === 'w',
    gameOver: false, moveCount: 0,
    capturedByPlayer: [], capturedByOpponent: [],
    moveHistory: [], botThinking: false
  };

  engine.create();
  clock = new ChessClock(tc.time, tc.increment);

  el.innerHTML = `
    <div class="chess-layout" style="display:flex;flex-direction:column;height:100%;background:#1a1a2e;">
      <!-- Opponent Bar -->
      <div class="chess-bar" style="display:flex;align-items:center;justify-content:space-between;padding:6px 12px;background:#0f0f1e;">
        <div style="display:flex;align-items:center;gap:8px;">
          <div style="width:32px;height:32px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;overflow:hidden;">
            <img src="https://stockfishapi.caprover.al-arcade.com/portraits/${botId || 'amina'}.png" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display='none';this.parentNode.innerHTML='${emoji('robot', '🤖', 14).replace(/'/g, "\\'")}'">
          </div>
          <div>
            <div style="font-size:13px;font-weight:600;color:#f8fafc;" id="opponent-name">${mode === 'bot' ? (botId || 'Bot') : 'Opponent'}</div>
            <div id="opponent-captured" style="font-size:11px;color:#94a3b8;min-height:14px;letter-spacing:1px;"></div>
          </div>
        </div>
        <div id="clock-opponent" class="chess-clock" style="font-size:18px;font-weight:700;font-family:Inter,monospace;background:#1e1e3a;padding:4px 12px;border-radius:6px;color:#f8fafc;min-width:60px;text-align:center;">${clock.format(tc.time)}</div>
      </div>

      <!-- Board -->
      <div id="board-container" style="flex:1;display:flex;align-items:center;justify-content:center;padding:2px 4px;position:relative;min-height:0;">
        <div id="bot-thinking" style="display:none;position:absolute;top:8px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.8);color:#E4AC38;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:600;z-index:10;">
          ${t('game.thinking')} <span class="pulse">${emoji('thinking_dots', '●●●', 12)}</span>
        </div>
        <div id="promo-dialog" style="display:none;position:absolute;z-index:20;background:#1e1e3a;border-radius:8px;padding:8px;box-shadow:0 8px 32px rgba(0,0,0,0.8);border:1px solid rgba(255,255,255,0.1);"></div>
      </div>

      <!-- Player Bar -->
      <div class="chess-bar" style="display:flex;align-items:center;justify-content:space-between;padding:6px 12px;background:#0f0f1e;">
        <div style="display:flex;align-items:center;gap:8px;">
          <div style="width:32px;height:32px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;font-size:14px;color:#f8fafc;">${emoji('person', '👤', 14)}</div>
          <div>
            <div style="font-size:13px;font-weight:600;color:#f8fafc;">${store.get('player.username') || store.get('player.display_name') || 'You'}</div>
            <div id="player-captured" style="font-size:11px;color:#94a3b8;min-height:14px;letter-spacing:1px;"></div>
          </div>
        </div>
        <div id="clock-player" class="chess-clock" style="font-size:18px;font-weight:700;font-family:Inter,monospace;background:#1e1e3a;padding:4px 12px;border-radius:6px;color:#f8fafc;min-width:60px;text-align:center;">${clock.format(tc.time)}</div>
      </div>

      <!-- Opening Name + Material -->
      <div style="display:flex;justify-content:space-between;align-items:center;padding:2px 12px;background:#0f0f1e;">
        <div id="opening-name" style="font-size:11px;color:#64748b;font-style:italic;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:70%;"></div>
        <div id="material-diff" style="font-size:12px;font-weight:700;font-family:Inter,monospace;color:#E4AC38;"></div>
      </div>
      <!-- Move List -->
      <div id="move-list" style="max-height:44px;overflow-x:auto;white-space:nowrap;padding:3px 12px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.05);font-family:Inter,monospace;font-size:12px;color:#94a3b8;display:flex;gap:4px;align-items:center;">
        <span style="color:#475569;">1.</span>
      </div>

      <!-- Controls -->
      <div style="display:flex;gap:6px;padding:8px 12px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.05);">
        <button class="ctrl-btn" id="btn-resign">${emoji('flag', '⚐', 12)} ${t('game.resign')}</button>
        <button class="ctrl-btn" id="btn-draw">½ ${t('game.draw')}</button>
        <button class="ctrl-btn" id="btn-flip">⟲ ${t('game.flip')}</button>
      </div>
    </div>
    <style>
      .ctrl-btn { flex:1;background:#1e1e3a;border:1px solid rgba(255,255,255,0.08);color:#94a3b8;font-size:12px;font-weight:600;padding:8px;border-radius:6px;cursor:pointer;font-family:inherit;transition:background 0.15s; }
      .ctrl-btn:active { background:#2a2a5a;transform:scale(0.97); }
      .chess-clock.low-time { color:#EF4444!important;animation:clockPulse 1s infinite; }
      @keyframes clockPulse { 0%,100%{opacity:1}50%{opacity:0.5} }
    </style>
  `;

  const boardContainer = el.querySelector('#board-container');
  board = new ChessBoard(boardContainer, {
    flipped: playerColor === 'b',
    interactive: true,
    onMove: (from, to) => handlePlayerMove(el, from, to)
  });

  board.canSelect = (piece) => {
    if (gameState.gameOver || gameState.botThinking) return false;
    if (!gameState.isPlayerTurn) return false;
    const pieceColor = piece === piece.toUpperCase() ? 'w' : 'b';
    return pieceColor === playerColor;
  };

  board.showLegalMoves = (square) => {
    board.highlights.legalMoves = engine.legalMoves(square);
  };

  board.setPosition(engine.fen());

  // Clock
  clock.onTick = (w, b) => {
    const playerEl = el.querySelector('#clock-player');
    const opponentEl = el.querySelector('#clock-opponent');
    if (playerColor === 'w') {
      playerEl.textContent = clock.format(w);
      opponentEl.textContent = clock.format(b);
      playerEl.classList.toggle('low-time', clock.isLowTime('w'));
      opponentEl.classList.toggle('low-time', clock.isLowTime('b'));
    } else {
      playerEl.textContent = clock.format(b);
      opponentEl.textContent = clock.format(w);
      playerEl.classList.toggle('low-time', clock.isLowTime('b'));
      opponentEl.classList.toggle('low-time', clock.isLowTime('w'));
    }
  };

  clock.onFlag = (color) => endGame(color === playerColor ? 'loss' : 'win', 'timeout');

  // Controls
  el.querySelector('#btn-resign').addEventListener('click', () => {
    if (gameState.gameOver) return;
    if (confirm('هل أنت متأكد من الاستسلام؟')) {
      audio.play('gameOver', 'game');
      endGame('loss', 'resign');
    }
  });
  el.querySelector('#btn-draw').addEventListener('click', () => {
    if (gameState.gameOver) return;
    audio.play('click');
    if (gameState.mode === 'bot') {
      // Bot has 50% chance of accepting draw
      if (Math.random() < 0.5) {
        endGame('draw', 'agreement');
      } else {
        // Bot declines - show message
        const msg = document.createElement('div');
        msg.textContent = 'الخصم رفض التعادل';
        msg.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.85);color:#F87171;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;z-index:30;pointer-events:none;';
        el.querySelector('#board-container').appendChild(msg);
        setTimeout(() => msg.remove(), 2000);
      }
    } else if (gameState.mode === 'live' && gameState.matchId) {
      net.post('game.php', {
        action: 'move',
        match_id: gameState.matchId,
        game_state: JSON.stringify({ draw_offer: store.get('auth.userId') })
      });
    }
  });
  el.querySelector('#btn-flip').addEventListener('click', () => { audio.play('click'); board.flip(); });

  // Create a real match record for bot games (so they appear in history)
  if (mode === 'bot' && !matchId) {
    net.post('game.php', {
      action: 'start',
      game_key: 'chess',
      mode: 'bot',
      time_control: timeControl,
      bot_id: botId
    }).then(data => {
      if (data && data.id) gameState.matchId = data.id;
    }).catch(() => {});
  }

  // Start bot if playing as black
  if (playerColor === 'b' && mode === 'bot') {
    clock.start('w');
    requestBotMove(el);
  }

  // Live mode: start polling for opponent moves
  if (mode === 'live' && matchId) {
    startLivePolling(el);
    if (playerColor === 'b') {
      gameState.isPlayerTurn = false;
      clock.start('w');
    }

    // Fetch and render opponent profile bar
    const opponentId = params.opponentId || (playerColor === 'w' ? params.blackPlayerId : params.whitePlayerId);
    if (opponentId) {
      mp.fetchOpponentProfile(opponentId).then(opp => {
        if (opp && !opp.error) {
          const oppBar = el.querySelector('.chess-bar');
          if (oppBar) {
            const nameEl = oppBar.querySelector('#opponent-name');
            if (nameEl) nameEl.textContent = opp.display_name || opp.username || 'خصم';
          }
        }
      });
    }
    mp.startDisconnectWatch(matchId, 'chess', 60000);

    // Synced emotes — animate from OPPONENT bar to center
    mp.onEmoteReceived((emote) => {
      const boardContainer = el.querySelector('#board-container');
      const oppBar = el.querySelector('.chess-bar'); // opponent bar is first chess-bar
      emoteSystem.showReceived(boardContainer, emote.key === 'gg' ? emoji('handshake', '🤝', 24) : emote.key === 'good_move' ? '👏' : '😮', oppBar);
      audio.play('notification');
    });
  }

  // Emote system
  const emoteContainer = el.querySelector('#board-container');
  emoteSystem.create(emoteContainer, (emote) => {
    audio.play('notification');
    // Animate from MY player bar to center
    const myBar = el.querySelectorAll('.chess-bar')[1]; // player bar is second
    emoteSystem.showReceived(emoteContainer, emote.emoji, myBar);
    // Sync to opponent in live mode
    if (gameState.mode === 'live' && matchId) {
      mp.sendEmote(matchId, 'chess', emote.key);
    }
  });

  bus.emit('game:started', { gameKey: 'chess', matchId, opponent: botId, mode });
}

function handlePlayerMove(el, from, to) {
  const moves = engine.legalMoves(from);
  const legalMove = moves.find(m => m.to === to);
  if (!legalMove) return;

  // Check promotion
  const piece = engine.get().get(from);
  if (piece && piece.type === 'p') {
    const rank = to[1];
    if ((piece.color === 'w' && rank === '8') || (piece.color === 'b' && rank === '1')) {
      showPromotionDialog(el, from, to, piece.color);
      return;
    }
  }

  executeMove(el, from, to);
}

function showPromotionDialog(el, from, to, color) {
  const dialog = el.querySelector('#promo-dialog');
  const pieces = ['q', 'r', 'b', 'n'];
  const names = { q: '♛', r: '♜', b: '♝', n: '♞' };
  if (color === 'w') { names.q = '♕'; names.r = '♖'; names.b = '♗'; names.n = '♘'; }

  dialog.style.display = 'flex';
  dialog.style.gap = '8px';
  dialog.innerHTML = pieces.map(p => `
    <div data-piece="${p}" style="width:44px;height:44px;display:flex;align-items:center;justify-content:center;font-size:28px;cursor:pointer;border-radius:6px;background:#2a2a5a;border:1px solid rgba(255,255,255,0.1);transition:background 0.15s;"
         onmouseenter="this.style.background='#3a3a7a'"
         onmouseleave="this.style.background='#2a2a5a'">
      ${names[p]}
    </div>
  `).join('');

  dialog.querySelectorAll('[data-piece]').forEach(btn => {
    btn.addEventListener('click', () => {
      dialog.style.display = 'none';
      executeMove(el, from, to, btn.dataset.piece);
    });
  });
}

function executeMove(el, from, to, promotion) {
  const m = engine.move(from, to, promotion || undefined);
  if (!m) return;

  gameState.moveCount++;
  // Animate piece sliding from → to, THEN update board state
  board.animateMove(from, to, () => {
    board.setPosition(engine.fen());
    board.setLastMove(from, to);
  });

  // Sound + Juice
  if (m.san.includes('#')) {
    audio.play('gameOver', 'game');
    juice.shake(el, 6, 400);
    juice.flash('#fff', 200);
    juice.hapticHeavy();
  } else if (m.san.includes('+')) {
    audio.play('check', 'game');
    juice.shake(el, 3, 200);
    juice.hapticMedium();
  } else if (m.captured) {
    audio.play('capture', 'game');
    juice.shake(el, 2, 150);
    juice.hapticLight();
    // Particle burst at capture square
    const captureXY = board.squareToXY(to);
    const boardRect = board.canvas.getBoundingClientRect();
    juice.burst(boardRect.left + captureXY.x + board.squareSize/2, boardRect.top + captureXY.y + board.squareSize/2,
      { count: 8, colors: ['#EF4444', '#F97316', '#FBBF24'], size: 6, spread: 60, duration: 500 });
  } else if (m.san === 'O-O' || m.san === 'O-O-O') {
    audio.play('castle', 'game');
    juice.hapticLight();
  } else {
    audio.play('move', 'game');
  }

  // Captured pieces
  if (m.captured) {
    if (m.color === gameState.playerColor) {
      gameState.capturedByPlayer.push(m.captured);
    } else {
      gameState.capturedByOpponent.push(m.captured);
    }
    updateCapturedDisplay(el);
  }

  // Check indicator
  if (engine.isCheck()) {
    board.setCheck(findKing(engine.turn()));
  } else {
    board.highlights.check = null;
    board.draw();
  }

  // Move list
  updateMoveList(el, m);

  // Clock
  if (gameState.moveCount === 1) {
    clock.start(engine.turn());
  } else {
    clock.switch();
  }

  gameState.isPlayerTurn = false;

  if (engine.isGameOver()) {
    endGame(engine.getResult(gameState.playerColor), getEndReason());
    return;
  }

  if (gameState.mode === 'bot') {
    requestBotMove(el);
  } else if (gameState.mode === 'live') {
    // Send move to server, then poll for opponent's response
    sendLiveMove(el);
  }
}

async function requestBotMove(el) {
  gameState.botThinking = true;
  const thinkingEl = el.querySelector('#bot-thinking');
  thinkingEl.style.display = 'block';

  try {
    const data = await net.post('bots.php', {
      action: 'move',
      fen: engine.fen(),
      bot_id: gameState.botId
    });

    thinkingEl.style.display = 'none';
    gameState.botThinking = false;

    if (data.best_move && !gameState.gameOver) {
      const from = data.best_move.substring(0, 2);
      const to = data.best_move.substring(2, 4);
      const promo = data.best_move.length > 4 ? data.best_move[4] : undefined;

      const m = engine.move(from, to, promo);
      if (m) {
        // Animate bot's piece sliding smoothly
        board.animateMove(from, to, () => {
          board.setPosition(engine.fen());
          board.setLastMove(from, to);
        });

        if (m.san.includes('#')) audio.play('gameOver', 'game');
        else if (m.san.includes('+')) audio.play('check', 'game');
        else if (m.captured) audio.play('capture', 'game');
        else if (m.san === 'O-O' || m.san === 'O-O-O') audio.play('castle', 'game');
        else audio.play('move', 'game');

        if (m.captured) {
          gameState.capturedByOpponent.push(m.captured);
          updateCapturedDisplay(el);
        }

        if (engine.isCheck()) {
          board.setCheck(findKing(engine.turn()));
        } else {
          board.highlights.check = null;
          board.draw();
        }

        updateMoveList(el, m);
        clock.switch();
        gameState.isPlayerTurn = true;
        gameState.moveCount++;

        if (engine.isGameOver()) {
          endGame(engine.getResult(gameState.playerColor), getEndReason());
        }
      }
    }
  } catch (e) {
    thinkingEl.style.display = 'none';
    gameState.botThinking = false;
    setTimeout(() => requestBotMove(el), 2000);
  }
}

function updateCapturedDisplay(el) {
  const pieceSymbols = { p: '♟', n: '♞', b: '♝', r: '♜', q: '♛', k: '♚' };
  const pieceOrder = ['q', 'r', 'b', 'n', 'p'];

  const sortCaptures = (arr) => arr.sort((a, b) => pieceOrder.indexOf(a) - pieceOrder.indexOf(b));

  const playerCaptures = sortCaptures([...gameState.capturedByPlayer]);
  const opponentCaptures = sortCaptures([...gameState.capturedByOpponent]);

  el.querySelector('#player-captured').textContent = playerCaptures.map(p => pieceSymbols[p] || p).join('');
  el.querySelector('#opponent-captured').textContent = opponentCaptures.map(p => pieceSymbols[p] || p).join('');
}

function updateMoveList(el, m) {
  gameState.moveHistory.push(m);
  const moveList = el.querySelector('#move-list');
  const history = gameState.moveHistory;

  let html = '';
  for (let i = 0; i < history.length; i += 2) {
    const moveNum = Math.floor(i / 2) + 1;
    const white = history[i]?.san || '';
    const black = history[i + 1]?.san || '';
    html += `<span style="color:#475569;">${moveNum}.</span>`;
    html += `<span style="color:#f8fafc;font-weight:500;">${white}</span>`;
    if (black) html += `<span style="color:#e2e8f0;">${black}</span>`;
  }
  moveList.innerHTML = html;
  moveList.scrollLeft = moveList.scrollWidth;

  // Update opening name
  const openingEl = el.querySelector('#opening-name');
  if (openingEl && history.length <= 12) {
    const name = getOpeningName(history);
    if (name) openingEl.textContent = name;
  }

  // Update material difference
  const matEl = el.querySelector('#material-diff');
  if (matEl) {
    const adv = getMaterialAdvantage(engine.fen(), gameState.playerColor);
    matEl.textContent = formatAdvantage(adv);
    matEl.style.color = adv > 0 ? '#34D399' : adv < 0 ? '#F87171' : '#64748b';
  }
}

function findKing(color) {
  const boardState = engine.get().board();
  for (let r = 0; r < 8; r++) {
    for (let c = 0; c < 8; c++) {
      const p = boardState[r][c];
      if (p && p.type === 'k' && p.color === color) {
        return String.fromCharCode(97 + c) + String(8 - r);
      }
    }
  }
  return null;
}

function getEndReason() {
  if (engine.isCheckmate()) return 'checkmate';
  if (engine.isStalemate()) return 'stalemate';
  if (engine.isThreefoldRepetition()) return 'threefold';
  if (engine.isInsufficientMaterial()) return 'insufficient';
  return 'draw';
}

// ===== LIVE MULTIPLAYER =====
let livePoller = null;
let lastKnownMoveCount = 0;

async function sendLiveMove(el) {
  if (!gameState.matchId) return;
  gameState.moveCount;
  lastKnownMoveCount = gameState.moveCount;
  try {
    await net.post('game.php', {
      action: 'move',
      match_id: gameState.matchId,
      fen: engine.fen(),
      move: JSON.stringify(gameState.moveHistory),
      move_count: gameState.moveCount
    });
  } catch (e) {}
}

function startLivePolling(el) {
  lastKnownMoveCount = 0;
  livePoller = setInterval(async () => {
    if (gameState.gameOver) { clearInterval(livePoller); return; }
    if (gameState.isPlayerTurn) return; // Only poll when waiting for opponent

    try {
      const data = await net.post('game.php', { action: 'get', match_id: gameState.matchId });
      if (!data || data.error) return;

      // Update connection status (opponent is alive if data comes back)
      mp.updateConnectionStatus(true);

      // Check for synced emotes from opponent
      const myId = store.get('auth.userId');
      const emoteData = mp.checkForEmote(data.game_state, myId);
      if (emoteData) {
        const boardContainer = el.querySelector('#board-container');
        const oppBar = el.querySelector('.chess-bar');
        emoteSystem.showReceived(boardContainer, emoteData.key === 'gg' ? emoji('handshake', '🤝', 24) : '👏', oppBar);
        audio.play('notification');
      }

      // Check if new move arrived
      if (data.move_count > lastKnownMoveCount) {
        lastKnownMoveCount = data.move_count;
        const newFen = data.current_fen;
        if (newFen && newFen !== engine.fen()) {
          engine.load(newFen);
          board.setPosition(newFen);
          audio.play('move', 'game');
          clock.switch();
          gameState.isPlayerTurn = true;
          gameState.moveCount = data.move_count;

          if (engine.isGameOver()) {
            endGame(engine.getResult(gameState.playerColor), getEndReason());
          }
        }
      }

      // Check if game ended (opponent resigned, etc.)
      if (data.status === 'completed' && !gameState.gameOver) {
        const result = data.result;
        if (result) {
          const isWin = (result === 'white_wins' && gameState.playerColor === 'w') ||
                        (result === 'black_wins' && gameState.playerColor === 'b');
          endGame(isWin ? 'win' : 'loss', 'resign');
        }
      }
    } catch (e) {}
  }, 2000);
}

function stopLivePolling() {
  if (livePoller) { clearInterval(livePoller); livePoller = null; }
}
// ===== END LIVE MULTIPLAYER =====

function endGame(result, reason) {
  if (gameState.gameOver) return;
  stopLivePolling();
  mp.cleanup();
  gameState.gameOver = true;
  clock.stop();
  board.interactive = false;

  if (result === 'win') audio.play('win', 'reward');
  else if (result === 'loss') audio.play('lose', 'game');
  else audio.play('gameOver', 'game');

  const coins = result === 'win' ? 50 : result === 'draw' ? 20 : 10;
  const xp = gameState.moveCount * 2;

  // Submit game result to backend for rating calculation
  const botElos = { amina: 500, tarek: 900, nour: 1100, omar: 1300, layla: 1500, ziad: 1700, grandmaster: 2100 };
  const opponentRating = botElos[gameState.botId] || 1200;

  net.post('game.php', {
    action: 'complete',
    match_id: gameState.matchId || 'local',
    result,
    fen: engine.fen(),
    pgn: engine.pgn(),
    opponent_rating: opponentRating,
    time_control: gameState.timeControl || 'rapid_10_0'
  }).then(data => {
    const ratingChange = data?.rating_change || (result === 'win' ? 12 : result === 'draw' ? 1 : -8);

    setTimeout(() => {
      scene.exitGameMode();
      scene.replace('chess-result', {
        result, reason, coins, xp, ratingChange,
        ratingBefore: data?.rating_before,
        ratingAfter: data?.rating_after,
        moves: gameState.moveCount,
        pgn: engine.pgn(),
        mode: gameState.mode,
        botId: gameState.botId,
        playerColor: gameState.playerColor,
        capturedByPlayer: gameState.capturedByPlayer,
        capturedByOpponent: gameState.capturedByOpponent,
        moveHistory: gameState.moveHistory,
        finalFen: engine.fen()
      });
      bus.emit('game:ended', { gameKey: 'chess', result, reason, mode: gameState.mode });
      bus.emit('coins:earned', { amount: coins });
      bus.emit('xp:earned', { amount: xp });
    }, 1000);
  }).catch(() => {
    setTimeout(() => {
      scene.exitGameMode();
      scene.replace('chess-result', {
        result, reason, coins, xp,
        ratingChange: result === 'win' ? 12 : result === 'draw' ? 1 : -8,
        moves: gameState.moveCount,
        pgn: engine.pgn(),
        mode: gameState.mode,
        botId: gameState.botId,
        playerColor: gameState.playerColor,
        capturedByPlayer: gameState.capturedByPlayer,
        capturedByOpponent: gameState.capturedByOpponent,
        moveHistory: gameState.moveHistory,
        finalFen: engine.fen()
      });
      bus.emit('game:ended', { gameKey: 'chess', result, reason, mode: gameState.mode });
    }, 1000);
  });
}
