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 * as modal from '../../../core/modal.js';
import { emoji } from '../../../core/theme.js';
import * as matchLive from '../../../core/match-live.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,
    tournamentId: params.tournamentId || null,
    tournamentRound: params.tournamentRound || null
  };

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

  // If recovering from a refresh, fetch current state from server and fix color
  if (params.recovered && matchId) {
    gameState._recovering = true;
    net.post('game.php', { action: 'get', match_id: matchId }).then(data => {
      if (!data || data.error) { gameState._recovering = false; return; }

      // If game already ended (opponent resigned while we were away)
      if (data.status === 'completed') {
        const myId = store.get('auth.userId');
        const isWhite = data.white_player_id === myId;
        const isWin = (data.result === 'white_wins' && isWhite) || (data.result === 'black_wins' && !isWhite);
        endGame(isWin ? 'win' : data.result === 'draw' ? 'draw' : 'loss', 'resign');
        return;
      }

      // Fix color: determine from match data which side we are
      const myId = store.get('auth.userId');
      if (data.white_player_id === myId) {
        gameState.playerColor = 'w';
        if (board) board.flipped = false;
      } else {
        gameState.playerColor = 'b';
        if (board) board.flipped = true;
      }

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

      // Load position
      if (data.current_fen) {
        engine.load(data.current_fen);
        if (board) board.setPosition(data.current_fen);
        gameState.moveCount = data.move_count || 0;
        lastKnownMoveCount = data.move_count || 0;

        // Determine whose turn
        const turnFromFen = data.current_fen.split(' ')[1];
        gameState.isPlayerTurn = turnFromFen === gameState.playerColor;
        if (!gameState.isPlayerTurn) clock.start(turnFromFen);
        else clock.start(gameState.playerColor);

        // Show check highlight if king is in check
        if (engine.isCheck()) {
          board.setCheck(findKing(engine.turn()));
        }
      }

      // Restore clocks
      if (data.white_time_remaining_ms) clock.white = data.white_time_remaining_ms;
      if (data.black_time_remaining_ms) clock.black = data.black_time_remaining_ms;

      if (board) board.draw();
      gameState._recovering = false;
    }).catch(() => { gameState._recovering = false; });
  }

  el.innerHTML = `
    <div class="chess-layout" style="display:flex;flex-direction:column;height:100%;background:#0f0f1e;justify-content:center;">
      <!-- Opponent Bar -->
      <div class="chess-bar" style="display:flex;align-items:center;justify-content:space-between;padding:8px 14px;background:#0f0f1e;">
        <div style="display:flex;align-items:center;gap:10px;">
          <div id="opponent-avatar" style="width:36px;height:36px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;overflow:hidden;border:2px solid ${mode === 'bot' ? '#64748b' : '#3B82F6'};">
            ${mode === 'bot' ? `<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.textContent='🤖'">` : '<span style="font-size:16px;">👤</span>'}
          </div>
          <div>
            <div style="font-size:13px;font-weight:600;color:#f8fafc;" id="opponent-name">${mode === 'bot' ? (botId || 'Bot') : 'جاري التحميل...'}</div>
            <div style="display:flex;gap:6px;align-items:center;">
              <div id="opponent-level" style="font-size:10px;color:#64748b;">${mode === 'bot' ? 'بوت' : ''}</div>
              <div id="opponent-captured" style="font-size:11px;color:#94a3b8;letter-spacing:1px;"></div>
            </div>
          </div>
        </div>
        <div id="clock-opponent" class="chess-clock">${clock.format(tc.time)}</div>
      </div>

      <!-- Board -->
      <div id="board-container" style="flex:0 0 auto;display:flex;align-items:center;justify-content:center;padding:4px 6px;position:relative;">
        <div id="bot-thinking" style="display:none;position:absolute;top:8px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.85);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:8px 14px;background:#0f0f1e;">
        <div style="display:flex;align-items:center;gap:10px;">
          <div style="width:36px;height:36px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;overflow:hidden;border:2px solid var(--gold, #E4AC38);">
            ${store.get('player.avatar_url') ? `<img src="${store.get('player.avatar_url')}" style="width:100%;height:100%;object-fit:cover;">` : `<span style="font-size:16px;">👤</span>`}
          </div>
          <div>
            <div style="font-size:13px;font-weight:600;color:#f8fafc;">${store.get('player.display_name') || store.get('player.username') || 'أنت'}</div>
            <div style="display:flex;gap:6px;align-items:center;">
              <span style="font-size:10px;color:#64748b;">Lv.${store.get('player.level') || 1}</span>
              <div id="player-captured" style="font-size:11px;color:#94a3b8;letter-spacing:1px;"></div>
            </div>
          </div>
          <button id="emote-inline-toggle" style="width:32px;height:32px;border-radius:50%;background:#1a1a2e;border:1px solid rgba(255,255,255,0.08);color:#f8fafc;font-size:14px;cursor:pointer;display:flex;align-items:center;justify-content:center;margin-inline-start:4px;">💬</button>
        </div>
        <div id="clock-player" class="chess-clock active">${clock.format(tc.time)}</div>
      </div>

      <!-- Opening Name + Material -->
      <div style="display:flex;justify-content:space-between;align-items:center;padding:2px 14px;">
        <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:'SF Mono',monospace;color:#E4AC38;"></div>
      </div>
      <!-- Move List -->
      <div id="move-list" style="max-height:40px;overflow-x:auto;white-space:nowrap;padding:4px 14px;font-family:'SF Mono',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:8px;padding:10px 14px;padding-bottom:max(10px, env(safe-area-inset-bottom, 0px));">
        <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>
      .chess-layout { gap: 0; }
      .chess-clock { font-size:18px;font-weight:700;font-family:'SF Mono',Inter,monospace;background:#1a1a2e;padding:6px 14px;border-radius:8px;color:#94a3b8;min-width:64px;text-align:center;border:1px solid rgba(255,255,255,0.06); }
      .chess-clock.active { color:#f8fafc;border-color:rgba(255,255,255,0.15); }
      .chess-clock.low-time { color:#EF4444!important;animation:clockPulse 1s infinite;border-color:rgba(239,68,68,0.3); }
      .ctrl-btn { flex:1;background:#1a1a2e;border:1px solid rgba(255,255,255,0.08);color:#e2e8f0;font-size:13px;font-weight:600;padding:12px 8px;border-radius:10px;cursor:pointer;font-family:inherit;transition:background 0.15s,transform 0.1s;min-height:48px; }
      .ctrl-btn:active { background:#2a2a5a;transform:scale(0.95); }
      @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', async () => {
    if (gameState.gameOver) return;
    const confirmed = await modal.confirm('هل أنت متأكد من الاستسلام؟', {
      title: 'استسلام',
      icon: '🏳️',
      confirmText: 'نعم، استسلم',
      cancelText: 'تراجع',
      danger: true
    });
    if (!confirmed) return;
    audio.play('gameOver', 'game');
    if (gameState.mode === 'live' && gameState.matchId) {
      await net.post('game.php', { action: 'resign', match_id: gameState.matchId }).catch(() => {});
    }
    endGame('loss', 'resign');
  });
  el.querySelector('#btn-draw').addEventListener('click', () => {
    if (gameState.gameOver) return;
    audio.play('click');
    if (gameState.mode === 'bot') {
      if (Math.random() < 0.5) {
        endGame('draw', 'agreement');
      } else {
        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) {
      const userId = store.get('auth.userId');
      net.post('game.php', {
        action: 'move',
        match_id: gameState.matchId,
        game_state: JSON.stringify({ draw_offer: userId, draw_offer_t: Date.now() })
      });
      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:#E4AC38;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(), 2500);
    }
  });
  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 match session (enables reconnection on refresh)
  if (mode === 'live' && matchId) {
    matchLive.start(matchId, 'chess', {
      onMove: (data) => {
        // match-session polls every 2s — process all game events here
        handleLivePollData(el, data);
      },
      onGameEnd: (data) => {
        if (!gameState.gameOver) endGame('loss', 'abandon');
      }
    });
    if (playerColor === 'b') {
      gameState.isPlayerTurn = false;
      clock.start('w');
    }

    // Fetch and render opponent profile bar (photo, name, level)
    let opponentId = params.opponentId;
    // If no opponentId in params, get it from the match data
    if (!opponentId && matchId) {
      net.post('game.php', { action: 'get', match_id: matchId }).then(matchData => {
        if (matchData && !matchData.error) {
          const myId = store.get('auth.userId');
          const oppId = matchData.white_player_id === myId ? matchData.black_player_id : matchData.white_player_id;
          if (oppId) fetchAndRenderOpponent(el, oppId);
        }
      }).catch(() => {});
    }
    if (opponentId) {
      fetchAndRenderOpponent(el, opponentId);
    }
    mp.startDisconnectWatch(matchId, 'chess', 60000);

  }

  // Mount emote panel right after the player bar (second .chess-bar)
  const playerBar = el.querySelectorAll('.chess-bar')[1];
  const emoteContainer = el.querySelector('.chess-layout');
  emoteSystem.create(emoteContainer, (emote) => {
    audio.play('notification');
    emoteSystem.showReceived(emoteContainer, emote.emoji, playerBar);
    if (gameState.mode === 'live' && matchId) {
      mp.sendEmote(matchId, 'chess', emote.key);
    }
  });
  // Move emote panel to sit right after player bar
  const emotePanel = emoteContainer.querySelector('.emote-bar');
  if (emotePanel && playerBar && playerBar.nextSibling) {
    emoteContainer.insertBefore(emotePanel, playerBar.nextSibling);
  }

  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 lastKnownMoveCount = 0;

async function sendLiveMove(el) {
  if (!gameState.matchId) return;
  lastKnownMoveCount = gameState.moveCount;
  const lastMove = gameState.moveHistory[gameState.moveHistory.length - 1];
  try {
    await net.post('game.php', {
      action: 'move',
      match_id: gameState.matchId,
      fen: engine.fen(),
      move: JSON.stringify(gameState.moveHistory),
      move_count: gameState.moveCount,
      white_time_remaining_ms: clock.white,
      black_time_remaining_ms: clock.black,
      game_state: JSON.stringify({
        last_move: lastMove ? { from: lastMove.from, to: lastMove.to, san: lastMove.san, promotion: lastMove.promotion || null } : null
      })
    });
  } catch (e) {}
}

function handleLivePollData(el, data) {
  if (!data || data.error) return;
  if (gameState.gameOver) return;
  if (gameState._recovering) return;

  mp.updateConnectionStatus(true);

  // Emotes — always check regardless of whose turn
  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, emoteSystem.getEmojiForKey(emoteData.key), oppBar);
    audio.play('notification');
  }

  // Draw offer/response — always check
  checkDrawOffer(el, data.game_state, myId);
  checkDrawResponse(el, data.game_state, myId);

  // New move arrived — only process when waiting for opponent
  if (!gameState.isPlayerTurn && data.move_count > lastKnownMoveCount) {
    lastKnownMoveCount = data.move_count;
    const newFen = data.current_fen;
    if (newFen && newFen !== engine.fen()) {
      const oldFen = engine.fen();

      // Get move info from game_state (reliable) or fall back to FEN diff
      const gs = data.game_state ? (typeof data.game_state === 'string' ? JSON.parse(data.game_state) : data.game_state) : {};
      const serverMove = gs.last_move;
      let moveFrom = serverMove?.from;
      let moveTo = serverMove?.to;
      let moveSan = serverMove?.san;

      // Fall back to FEN diff if game_state doesn't have the move
      if (!moveFrom || !moveTo) {
        const detected = detectLastMoveSquares(oldFen, newFen);
        if (detected) { moveFrom = detected.from; moveTo = detected.to; }
      }
      if (!moveSan) {
        moveSan = detectLastMoveSan(data, oldFen, newFen);
      }

      engine.load(newFen);

      // Animate the opponent's piece
      if (moveFrom && moveTo) {
        board.animateMove(moveFrom, moveTo, () => {
          board.setPosition(newFen);
          board.setLastMove(moveFrom, moveTo);
        });
      } else {
        board.setPosition(newFen);
      }

      // Play appropriate sound + juice
      if (moveSan && moveSan.includes('#')) {
        audio.play('gameOver', 'game');
        juice.shake(el, 6, 400);
        juice.hapticHeavy();
      } else if (moveSan && moveSan.includes('+')) {
        audio.play('check', 'game');
        juice.shake(el, 3, 200);
        juice.hapticMedium();
      } else if (isCapture(oldFen, newFen)) {
        audio.play('capture', 'game');
        juice.shake(el, 2, 150);
        juice.hapticLight();
        if (moveTo) {
          const captureXY = board.squareToXY(moveTo);
          if (captureXY) {
            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 (moveSan && (moveSan === 'O-O' || moveSan === 'O-O-O')) {
        audio.play('castle', 'game');
        juice.hapticLight();
      } else {
        audio.play('move', 'game');
      }

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

      // Sync clocks from server
      if (data.white_time_remaining_ms) clock.white = data.white_time_remaining_ms;
      if (data.black_time_remaining_ms) clock.black = data.black_time_remaining_ms;
      clock.switch();

      gameState.isPlayerTurn = true;
      gameState.moveCount = data.move_count;

      // Update move list + captured pieces from server history
      if (data.moves) {
        try {
          const moveHistory = typeof data.moves === 'string' ? JSON.parse(data.moves) : data.moves;
          if (Array.isArray(moveHistory) && moveHistory.length > gameState.moveHistory.length) {
            const newMove = moveHistory[moveHistory.length - 1];
            if (newMove) {
              gameState.moveHistory.push(newMove);
              updateMoveList(el, newMove);
              if (newMove.captured) {
                gameState.capturedByOpponent.push(newMove.captured);
                updateCapturedDisplay(el);
              }
            }
          }
        } catch (e) {}
      }

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

  // Game ended (resign, abandon, draw accepted by opponent)
  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');
      const isDraw = result === 'draw' || result === 'aborted';
      endGame(isWin ? 'win' : isDraw ? 'draw' : 'loss', result === 'aborted' ? 'abandon' : 'resign');
    }
  }
}

function detectLastMoveSan(data, oldFen, newFen) {
  if (data.moves) {
    try {
      const moves = typeof data.moves === 'string' ? JSON.parse(data.moves) : data.moves;
      if (Array.isArray(moves) && moves.length > 0) {
        const last = moves[moves.length - 1];
        return last?.san || null;
      }
    } catch (e) {}
  }
  return null;
}

function detectLastMoveSquares(oldFen, newFen) {
  const oldPieces = parseFenPieces(oldFen);
  const newPieces = parseFenPieces(newFen);
  let from = null, to = null;
  for (const sq of Object.keys(oldPieces)) {
    if (!newPieces[sq] && oldPieces[sq]) from = sq;
  }
  for (const sq of Object.keys(newPieces)) {
    if (!oldPieces[sq] || oldPieces[sq] !== newPieces[sq]) {
      if (newPieces[sq]) to = sq;
    }
  }
  if (from && to) return { from, to };
  return null;
}

function parseFenPieces(fen) {
  const pieces = {};
  const rows = fen.split(' ')[0].split('/');
  for (let r = 0; r < 8; r++) {
    let col = 0;
    for (const ch of rows[r]) {
      if (ch >= '1' && ch <= '8') col += parseInt(ch);
      else {
        pieces[String.fromCharCode(97 + col) + String(8 - r)] = ch;
        col++;
      }
    }
  }
  return pieces;
}

function isCapture(oldFen, newFen) {
  const oldCount = oldFen.split(' ')[0].replace(/[0-9/]/g, '').length;
  const newCount = newFen.split(' ')[0].replace(/[0-9/]/g, '').length;
  return newCount < oldCount;
}

let lastDrawOfferHandled = 0;

function checkDrawOffer(el, rawGameState, myId) {
  if (!rawGameState || gameState.gameOver) return;
  const gs = typeof rawGameState === 'string' ? JSON.parse(rawGameState) : rawGameState;
  if (!gs || !gs.draw_offer || gs.draw_offer === myId) return;
  const offerTime = gs.draw_offer_t || 0;
  if (offerTime <= lastDrawOfferHandled) return;
  lastDrawOfferHandled = offerTime;

  // Show accept/deny UI
  const existing = el.querySelector('#draw-offer-dialog');
  if (existing) existing.remove();

  const dialog = document.createElement('div');
  dialog.id = 'draw-offer-dialog';
  dialog.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:#1e1e3a;border:1px solid rgba(228,172,56,0.4);border-radius:12px;padding:16px 20px;z-index:50;box-shadow:0 8px 32px rgba(0,0,0,0.7);text-align:center;min-width:220px;';
  dialog.innerHTML = `
    <div style="font-size:14px;font-weight:600;color:#f8fafc;margin-bottom:12px;">الخصم يعرض التعادل</div>
    <div style="display:flex;gap:10px;justify-content:center;">
      <button id="draw-accept" style="flex:1;padding:10px;background:#34D399;color:#000;font-weight:700;border:none;border-radius:8px;font-size:13px;cursor:pointer;font-family:inherit;">قبول ½</button>
      <button id="draw-reject" style="flex:1;padding:10px;background:#EF4444;color:#fff;font-weight:700;border:none;border-radius:8px;font-size:13px;cursor:pointer;font-family:inherit;">رفض</button>
    </div>
  `;

  el.querySelector('#board-container').appendChild(dialog);
  audio.play('notification');

  dialog.querySelector('#draw-accept').addEventListener('click', () => {
    dialog.remove();
    net.post('game.php', {
      action: 'draw',
      match_id: gameState.matchId
    });
    endGame('draw', 'agreement');
  });

  dialog.querySelector('#draw-reject').addEventListener('click', () => {
    dialog.remove();
    net.post('game.php', {
      action: 'move',
      match_id: gameState.matchId,
      game_state: JSON.stringify({ draw_offer: null, draw_offer_t: null, draw_declined: myId, draw_declined_t: Date.now() })
    });
    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);
  });

  // Auto-dismiss after 30s
  setTimeout(() => { if (dialog.parentNode) dialog.remove(); }, 30000);
}

let lastDrawDeclineHandled = 0;

function checkDrawResponse(el, rawGameState, myId) {
  if (!rawGameState || gameState.gameOver) return;
  const gs = typeof rawGameState === 'string' ? JSON.parse(rawGameState) : rawGameState;
  if (!gs) return;

  if (gs.draw_accepted) {
    endGame('draw', 'agreement');
    return;
  }

  if (gs.draw_declined && gs.draw_declined !== myId && (gs.draw_declined_t || 0) > lastDrawDeclineHandled) {
    lastDrawDeclineHandled = gs.draw_declined_t;
    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);
  }
}
// ===== END LIVE MULTIPLAYER =====

function fetchAndRenderOpponent(el, oppId) {
  mp.fetchOpponentProfile(oppId).then(opp => {
    if (opp && !opp.error) {
      const nameEl = el.querySelector('#opponent-name');
      const levelEl = el.querySelector('#opponent-level');
      const avatarEl = el.querySelector('#opponent-avatar');
      if (nameEl) nameEl.textContent = opp.display_name || opp.username || 'خصم';
      if (levelEl) levelEl.textContent = `Lv.${opp.level || 1}`;
      if (avatarEl && opp.avatar_url) {
        avatarEl.innerHTML = `<img src="${opp.avatar_url}" style="width:100%;height:100%;object-fit:cover;border-radius:50%;">`;
      }
    }
  }).catch(() => {});
}

function endGame(result, reason) {
  if (gameState.gameOver) return;
  mp.cleanup();
  matchLive.session.destroy(); // Clear recovery so homepage doesn't try to rejoin
  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);

    // Tournament mode: report result to tournament system
    if (gameState.tournamentId) {
      reportTournamentResult(result);
    }

    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(),
        tournamentId: gameState.tournamentId || null
      });
      bus.emit('game:ended', { gameKey: 'chess', result, reason, mode: gameState.mode });
      if (gameState.tournamentId) {
        bus.emit('tournament:match-ended', { tournamentId: gameState.tournamentId, result });
      }
      bus.emit('coins:earned', { amount: coins });
      bus.emit('xp:earned', { amount: xp });
    }, 1000);
  }).catch(() => {
    if (gameState.tournamentId) {
      reportTournamentResult(result);
    }
    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(),
        tournamentId: gameState.tournamentId || null
      });
      bus.emit('game:ended', { gameKey: 'chess', result, reason, mode: gameState.mode });
      if (gameState.tournamentId) {
        bus.emit('tournament:match-ended', { tournamentId: gameState.tournamentId, result });
      }
    }, 1000);
  });
}

function reportTournamentResult(result) {
  const mappedResult = gameState.playerColor === 'w'
    ? (result === 'win' ? 'white_wins' : result === 'loss' ? 'black_wins' : 'draw')
    : (result === 'win' ? 'black_wins' : result === 'loss' ? 'white_wins' : 'draw');

  net.post('tournament-match.php', {
    action: 'report-result',
    match_id: gameState.matchId,
    tournament_id: gameState.tournamentId,
    result: mappedResult
  }).catch(e => console.warn('[tournament] report error:', e));
}

