// EL3AB Analysis Controller - Post-game review with engine evaluation

const Analysis = {
  chess: null,
  gameData: null,
  gameId: null,
  moves: [],
  positions: [], // FEN at each position (index 0 = start)
  evaluations: [],
  currentMoveIndex: -1, // -1 = starting position
  playerColor: 'w',
  isAnalyzing: false,
  mistakeIndices: [],

  // ECO Opening lookup (top 100)
  ECO: {
    'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq': 'B00 King\'s Pawn',
    'rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq': 'D00 Queen\'s Pawn',
    'rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR b KQkq': 'A10 English Opening',
    'rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R b KQkq': 'A04 Reti Opening',
    'rnbqkbnr/pppp1ppp/4p3/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'C00 French Defense',
    'rnbqkbnr/pp1ppppp/2p5/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B10 Caro-Kann',
    'rnbqkbnr/pppppp1p/6p1/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B06 Modern Defense',
    'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3': 'B00 King\'s Pawn Opening',
    'rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'C20 Open Game',
    'rnbqkbnr/pppp1ppp/8/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq': 'C40 King\'s Knight Opening',
    'r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'C44 Open Game',
    'r1bqkbnr/pppp1ppp/2n5/4p3/2B1P3/5N2/PPPP1PPP/RNBQK2R b KQkq': 'C50 Italian Game',
    'r1bqkb1r/pppp1ppp/2n2n2/4p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq': 'C54 Italian Game: Giuoco Piano',
    'r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'C40 King\'s Knight',
    'r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq': 'C60 Ruy Lopez',
    'r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq': 'C65 Ruy Lopez: Berlin',
    'r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq': 'C70 Ruy Lopez: Morphy',
    'rnbqkb1r/pppppppp/5n2/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B02 Alekhine Defense',
    'rnbqkb1r/pppppppp/5n2/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A45 Indian Game',
    'rnbqkb1r/pppppp1p/5np1/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A48 King\'s Indian',
    'rnbqkb1r/pppppp1p/5np1/8/2PP4/8/PP2PPPP/RNBQKBNR b KQkq': 'E60 King\'s Indian Defense',
    'rnbqk2r/ppppppbp/5np1/8/2PP4/2N5/PP2PPPP/R1BQKBNR b KQkq': 'E61 King\'s Indian',
    'rnbqk2r/ppp1ppbp/3p1np1/8/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq': 'E70 King\'s Indian: Classical',
    'rnbqkb1r/pppp1ppp/4pn2/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A46 Indian Defense',
    'rnbqkb1r/pppp1ppp/4pn2/8/2PP4/8/PP2PPPP/RNBQKBNR b KQkq': 'E00 Catalan/Indian',
    'rnbqkb1r/p1pp1ppp/1p2pn2/8/2PP4/8/PP2PPPP/RNBQKBNR w KQkq': 'A40 Queen\'s Indian',
    'rnbqkb1r/pppp1ppp/4pn2/8/2PP4/5N2/PP2PPPP/RNBQKB1R b KQkq': 'E10 Queen\'s Pawn',
    'rnbqkb1r/pppp1ppp/4pn2/8/2PP4/2N5/PP2PPPP/R1BQKBNR b KQkq': 'E20 Nimzo-Indian',
    'rnbqk2r/pppp1ppp/4pn2/8/1bPP4/2N5/PP2PPPP/R1BQKBNR w KQkq': 'E21 Nimzo-Indian Defense',
    'rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'D00 Queen\'s Pawn Game',
    'rnbqkbnr/ppp1pppp/8/3p4/2PP4/8/PP2PPPP/RNBQKBNR b KQkq': 'D06 Queen\'s Gambit',
    'rnbqkbnr/ppp2ppp/4p3/3p4/2PP4/8/PP2PPPP/RNBQKBNR w KQkq': 'D30 Queen\'s Gambit Declined',
    'rnbqkbnr/ppp1pppp/8/3p4/2PP4/8/PP2PPPP/RNBQKBNR b KQkq c3': 'D06 Queen\'s Gambit',
    'rnbqkbnr/ppp2ppp/8/3pp3/2PP4/8/PP2PPPP/RNBQKBNR w KQkq': 'D06 QGD: Albin Counter',
    'rnbqkb1r/ppp1pppp/5n2/3p4/2PP4/8/PP2PPPP/RNBQKBNR w KQkq': 'D06 QGD',
    'rnbqkb1r/ppp1pppp/5n2/3p4/2PP4/5N2/PP2PPPP/RNBQKB1R b KQkq': 'D10 Slav Defense',
    'rnbqkb1r/pp2pppp/2p2n2/3p4/2PP4/5N2/PP2PPPP/RNBQKB1R w KQkq': 'D11 Slav',
    'rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e6': 'C20 King\'s Pawn Game',
    'rnbqkbnr/pppp1ppp/8/4p3/2P5/8/PP1PPPPP/RNBQKBNR w KQkq': 'A20 English: Reversed Sicilian',
    'rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B20 Sicilian Defense',
    'rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq': 'B27 Sicilian',
    'rnbqkbnr/pp1ppppp/3p4/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B50 Sicilian',
    'rnbqkbnr/pp1ppppp/8/2p5/3PP3/8/PPP2PPP/RNBQKBNR b KQkq': 'B21 Sicilian: Smith-Morra',
    'rnbqkbnr/pp2pppp/3p4/2p5/3PP3/5N2/PPP2PPP/RNBQKB1R b KQkq': 'B50 Sicilian',
    'rnbqkbnr/pp2pppp/3p4/8/3pP3/5N2/PPP2PPP/RNBQKB1R w KQkq': 'B54 Sicilian: Open',
    'r1bqkbnr/pp2pppp/2np4/8/3NP3/8/PPP2PPP/RNBQKB1R w KQkq': 'B40 Sicilian: Open Variation',
    'rnbqkbnr/pp2pppp/3p4/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B40 Sicilian',
    'r1bqkbnr/pp1ppppp/2n5/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B30 Sicilian',
    'r1bqkb1r/pp1ppppp/2n2n2/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B30 Sicilian',
    'rnbqkbnr/pp1p1ppp/4p3/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B40 Sicilian',
    'rnbqkb1r/pp1ppppp/5n2/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'B27 Sicilian',
    'r1bqkb1r/pp2pppp/2np1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq': 'B60 Sicilian Richter-Rauzer',
    'rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq': 'B90 Sicilian Najdorf',
    'r1b1kb1r/pp3ppp/1qnppn2/8/3NP3/2N1B3/PPPQ1PPP/R3KB1R w KQkq': 'B80 Sicilian Scheveningen',
    'r1bqkb1r/pp3ppp/2nppn2/8/3NP3/2N5/PPP1BPPP/R1BQK2R b KQkq': 'B80 Sicilian',
    'rnbqkbnr/pppp1p1p/8/6p1/4Pp2/8/PPPP1PPP/RNBQKBNR w KQkq': 'C30 King\'s Gambit',
    'rnbqkbnr/pppp1ppp/8/4p3/4PP2/8/PPPP2PP/RNBQKBNR b KQkq': 'C30 King\'s Gambit',
    'rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B01 Scandinavian',
    'rnbqkbnr/pppp1ppp/8/8/4Pp2/8/PPPP2PP/RNBQKBNR w KQkq': 'C30 KG Accepted',
    'rnbqkbnr/pppp1ppp/8/4p3/4P3/2N5/PPPP1PPP/R1BQKBNR b KQkq': 'C25 Vienna Game',
    'rnbqk2r/pppp1ppp/5n2/2b1p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq': 'C50 Italian: Giuoco Piano',
    'rnbqkb1r/pppp1ppp/5n2/4p3/2B1P3/8/PPPP1PPP/RNBQK1NR w KQkq': 'C42 Petrov Defense',
    'rnbqkb1r/pppp1ppp/5n2/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq': 'C42 Petrov Defense',
    'r1bqk2r/pppp1ppp/2n2n2/2b1p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq': 'C50 Italian: Two Knights',
    'r1bqkbnr/pppppppp/2n5/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B00 Nimzowitsch Defense',
    'rnbqkbnr/pp1ppppp/8/2p5/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A40 Benoni',
    'rnbqkb1r/pppppp1p/5np1/8/2P5/8/PP1PPPPP/RNBQKBNR w KQkq': 'A15 English: Anglo-Indian',
    'rnbqkbnr/pppppp1p/6p1/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A40 Modern',
    'rnbqkbnr/pppppp1p/6p1/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'B06 Modern Defense',
    'rnbqkbnr/pp1ppppp/2p5/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A00 Slav Setup',
    'rnbqkbnr/pppppp1p/6p1/8/8/5N2/PPPPPPPP/RNBQKB1R w KQkq': 'A04 Reti',
    'rnbqkbnr/ppppp1pp/8/5p2/4P3/8/PPPP1PPP/RNBQKBNR w KQkq': 'A02 Bird\'s Opening / From\'s Gambit',
    'rnbqkbnr/ppppp1pp/8/5p2/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A45 Dutch',
    'rnbqkbnr/ppppp1pp/8/5p2/2P5/8/PP1PPPPP/RNBQKBNR w KQkq': 'A10 English vs Dutch',
    'rnbqkbnr/ppppp1pp/8/5p2/8/5N2/PPPPPPPP/RNBQKB1R w KQkq': 'A04 Reti vs Dutch',
    'rnbqkbnr/pppppppp/8/8/8/2N5/PPPPPPPP/R1BQKBNR b KQkq': 'A00 Van\'t Kruijs',
    'rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b KQkq': 'A00 Ware Opening',
    'rnbqkbnr/pppppppp/8/8/1P6/8/P1PPPPPP/RNBQKBNR b KQkq': 'A00 Polish Opening',
    'rnbqkbnr/pppppppp/8/8/8/1P6/P1PPPPPP/RNBQKBNR b KQkq': 'A01 Larsen\'s Opening',
    'rnbqkbnr/pppppppp/8/8/8/6P1/PPPPPP1P/RNBQKBNR b KQkq': 'A00 Benko Opening',
    'rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b KQkq': 'A00 Anderssen Opening',
    'rnbqkb1r/ppp1pppp/3p1n2/8/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq': 'A41 Old Indian',
    'rnbqkb1r/ppp1pppp/3p1n2/8/2PP4/5N2/PP2PPPP/RNBQKB1R b KQkq': 'A41 Old Indian',
    'rnbqk2r/ppppppbp/5np1/8/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq': 'E62 King\'s Indian: Fianchetto',
    'rnbq1rk1/ppp1ppbp/3p1np1/8/2PPP3/2N2N2/PP3PPP/R1BQKB1R b KQ': 'E70 King\'s Indian',
    'rnbq1rk1/ppppppbp/5np1/8/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQ': 'E62 King\'s Indian: Fianchetto',
    'rnbqk2r/pppp1ppp/4pn2/8/1bPP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq': 'E40 Nimzo-Indian',
    'rnbqk2r/pppp1ppp/4pn2/8/1bPP4/2N5/PPQ1PPPP/R1B1KBNR b KQkq': 'E32 Nimzo-Indian: Classical',
    'rnbqk2r/pppp1ppp/4pn2/8/1bPP4/P1N5/1P2PPPP/R1BQKBNR b KQkq': 'E24 Nimzo-Indian: Samisch',
    'rnbqkb1r/p1pp1ppp/1p2pn2/8/2PP4/5N2/PP2PPPP/RNBQKB1R w KQkq': 'E12 Queen\'s Indian',
    'rnbqkb1r/p1pp1ppp/1p2pn2/8/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq': 'E12 Queen\'s Indian',
    'rn1qkb1r/pbpp1ppp/1p2pn2/8/2PP4/5NP1/PP2PP1P/RNBQKB1R b KQkq': 'E15 Queen\'s Indian',
    'rnbqkb1r/ppp2ppp/4pn2/3p4/2PP4/2N5/PP2PPPP/R1BQKBNR w KQkq': 'D30 QGD',
    'rnbqkb1r/ppp2ppp/4pn2/3p4/2PP4/5N2/PP2PPPP/RNBQKB1R w KQkq': 'D30 Queen\'s Gambit Declined',
    'rnbqkb1r/ppp2ppp/4pn2/3p4/2PP4/2N2N2/PP2PPPP/R1BQKB1R b KQkq': 'D35 QGD',
    'rnbqk2r/ppp1bppp/4pn2/3p4/2PP4/2N2N2/PP2PPPP/R1BQKB1R w KQkq': 'D37 QGD',
    'rnbqkb1r/pp3ppp/4pn2/2pp4/2PP4/2N2N2/PP2PPPP/R1BQKB1R w KQkq': 'D31 Semi-Slav',
    'rnbqkb1r/pp3ppp/2p1pn2/3p4/2PP4/2N2N2/PP2PPPP/R1BQKB1R w KQkq': 'D43 Semi-Slav',
    'rnbqkbnr/ppp1pppp/8/8/2pP4/8/PP2PPPP/RNBQKBNR w KQkq': 'D20 QGA',
    'rnbqkbnr/ppp1pppp/8/8/2pPP3/8/PP3PPP/RNBQKBNR b KQkq': 'D20 QGA',
    'rnbqkbnr/1pp1pppp/p7/8/2pPP3/5N2/PP3PPP/RNBQKB1R b KQkq': 'D25 QGA',
    'r1bqkbnr/pppppppp/2n5/8/3P4/8/PPP1PPPP/RNBQKBNR w KQkq': 'A40 Chigorin',
    'rnbqkbnr/pppppppp/8/8/8/5NP1/PPPPPP1P/RNBQKB1R b KQkq': 'A04 Reti: KIA',
  },

  async init(gameId) {
    this.gameId = gameId;
    this.chess = new Chess();

    Board.init('board', {
      onMove: null // Read-only in analysis mode
    });

    this.bindKeys();
    this.bindButtons();

    await this.loadGame();
  },

  async loadGame() {
    try {
      const data = await App.fetch('/api/analysis?id=' + this.gameId);
      if (!data || !data.game) {
        App.toast('لم يتم العثور على المباراة', 'error');
        return;
      }

      this.gameData = data.game;
      this.playerColor = data.game.player_color || 'w';

      // Parse PGN or replay moves from moves array
      var movesLoaded = false;

      if (data.game.pgn && data.game.pgn.trim().length > 0) {
        try {
          this.chess.load_pgn(data.game.pgn);
          movesLoaded = true;
        } catch(e) {}
      }

      // Build positions array
      const tempChess = new Chess();
      this.positions = [tempChess.fen()];
      this.moves = [];

      if (movesLoaded) {
        const replayChess = new Chess();
        const history = this.chess.history({ verbose: true });
        for (const move of history) {
          replayChess.move(move);
          this.positions.push(replayChess.fen());
          this.moves.push(move);
        }
      } else if (data.game.moves && data.game.moves.length > 0) {
        // Fallback: replay from moves array (SAN strings)
        var moveArr = data.game.moves;
        if (typeof moveArr === 'string') {
          try { moveArr = JSON.parse(moveArr); } catch(e) { moveArr = []; }
        }
        const replayChess = new Chess();
        for (var i = 0; i < moveArr.length; i++) {
          var san = typeof moveArr[i] === 'string' ? moveArr[i] : (moveArr[i].san || moveArr[i]);
          var result = replayChess.move(san);
          if (result) {
            this.positions.push(replayChess.fen());
            this.moves.push(result);
          }
        }
        this.chess.load(replayChess.fen());
      }

      // Load cached analysis if available
      if (data.has_analysis && data.analysis) {
        this.evaluations = data.analysis.evaluations || [];
        this.classifyMoves();
      }

      this.renderUI();
      this.goToMove(-1);

      document.getElementById('analysis-loading').style.display = 'none';
      document.getElementById('analysis-content').style.display = 'block';

    } catch (e) {
      App.toast('خطأ في تحميل المباراة', 'error');
    }
  },

  renderUI() {
    const game = this.gameData;

    // Player names - load from API cache if available
    document.getElementById('analysis-player-name').textContent = 'انت';
    const opponentEl = document.getElementById('analysis-opponent-name');
    opponentEl.textContent = game.bot_id || 'الخصم';

    if (game.bot_id && typeof App !== 'undefined') {
      App.cachedFetch('/api/bots.php', 60000).then(data => {
        if (data && data.bots) {
          const bot = data.bots.find(b => b.id === game.bot_id);
          if (bot) opponentEl.textContent = bot.name_ar.split(' ')[0];
        }
      }).catch(() => {});
    }

    // Opening detection
    const opening = this.detectOpening();
    if (opening) {
      document.getElementById('analysis-opening').textContent = opening;
    }

    // Render move list
    this.renderMoveList();

    // If we have evaluations, render graphs
    if (this.evaluations.length > 0) {
      this.renderEvalGraph();
      this.renderTimeGraph();
      this.renderCriticalMoments();
      this.calculateAccuracy();
    }
  },

  detectOpening() {
    // Check first several positions against ECO database
    for (let i = Math.min(this.positions.length - 1, 12); i >= 1; i--) {
      const fen = this.positions[i];
      // Strip move counters for lookup (just piece placement + active color + castling + en passant)
      const fenParts = fen.split(' ');
      const lookupKey = fenParts.slice(0, 3).join(' ');

      for (const [key, name] of Object.entries(this.ECO)) {
        if (lookupKey.startsWith(key.split(' ').slice(0, 3).join(' '))) {
          return name;
        }
      }
    }
    return null;
  },

  renderMoveList() {
    const container = document.getElementById('analysis-moves');
    if (!container) return;
    container.innerHTML = '';

    const history = this.moves;

    for (let i = 0; i < history.length; i += 2) {
      const pair = document.createElement('div');
      pair.className = 'analysis-move-pair';

      const num = document.createElement('span');
      num.className = 'analysis-move-number';
      num.textContent = (Math.floor(i / 2) + 1) + '.';
      pair.appendChild(num);

      // White move
      const whiteMove = document.createElement('span');
      whiteMove.className = 'analysis-move';
      whiteMove.dataset.index = i;
      whiteMove.onclick = () => this.goToMove(i);

      // Add classification badge
      const whiteClass = this.getMoveClassification(i);
      if (whiteClass) {
        const badge = document.createElement('span');
        badge.className = 'move-class move-class-' + whiteClass.type;
        badge.textContent = whiteClass.symbol;
        whiteMove.appendChild(badge);
      }

      const whiteText = document.createTextNode(history[i].san);
      whiteMove.appendChild(whiteText);
      pair.appendChild(whiteMove);

      // Black move
      if (history[i + 1]) {
        const blackMove = document.createElement('span');
        blackMove.className = 'analysis-move';
        blackMove.dataset.index = i + 1;
        blackMove.onclick = () => this.goToMove(i + 1);

        const blackClass = this.getMoveClassification(i + 1);
        if (blackClass) {
          const badge = document.createElement('span');
          badge.className = 'move-class move-class-' + blackClass.type;
          badge.textContent = blackClass.symbol;
          blackMove.appendChild(badge);
        }

        const blackText = document.createTextNode(history[i + 1].san);
        blackMove.appendChild(blackText);
        pair.appendChild(blackMove);
      }

      container.appendChild(pair);
    }
  },

  getMoveClassification(moveIndex) {
    if (!this.evaluations || this.evaluations.length < 2) return null;
    if (moveIndex >= this.evaluations.length - 1) return null;

    const evalBefore = this.evaluations[moveIndex] ? this.evaluations[moveIndex].evaluation : 0;
    const evalAfter = this.evaluations[moveIndex + 1] ? this.evaluations[moveIndex + 1].evaluation : 0;

    // Determine who moved (even = white, odd = black)
    const isWhiteMove = moveIndex % 2 === 0;
    // Eval change from the mover's perspective
    const evalChange = isWhiteMove ? (evalAfter - evalBefore) : (evalBefore - evalAfter);

    // Classification thresholds
    if (evalChange >= 1.5) return { type: 'brilliant', symbol: '!!' };
    if (evalChange >= 0.5) return { type: 'great', symbol: '!' };
    if (evalChange >= -0.1) return { type: 'good', symbol: '' };
    if (evalChange >= -0.5) return { type: 'inaccuracy', symbol: '?!' };
    if (evalChange >= -1.0) return { type: 'mistake', symbol: '?' };
    if (evalChange < -1.0) return { type: 'blunder', symbol: '??' };

    return null;
  },

  classifyMoves() {
    this.mistakeIndices = [];
    for (let i = 0; i < this.moves.length; i++) {
      const classification = this.getMoveClassification(i);
      if (classification && (classification.type === 'mistake' || classification.type === 'blunder' || classification.type === 'inaccuracy')) {
        // Only track the player's mistakes
        const isPlayerMove = (i % 2 === 0 && this.playerColor === 'w') || (i % 2 === 1 && this.playerColor === 'b');
        if (isPlayerMove) {
          this.mistakeIndices.push(i);
        }
      }
    }
  },

  calculateAccuracy() {
    if (this.evaluations.length < 2) return;

    let whiteTotal = 0, whiteCount = 0;
    let blackTotal = 0, blackCount = 0;

    for (let i = 0; i < this.moves.length; i++) {
      if (i >= this.evaluations.length - 1) break;

      const evalBefore = this.evaluations[i].evaluation || 0;
      const evalAfter = this.evaluations[i + 1].evaluation || 0;
      const isWhiteMove = i % 2 === 0;
      const loss = isWhiteMove ? Math.max(0, evalBefore - evalAfter) : Math.max(0, evalAfter - evalBefore);

      // Convert centipawn loss to accuracy percentage (roughly)
      const accuracy = Math.max(0, 100 - (loss * 20));

      if (isWhiteMove) {
        whiteTotal += accuracy;
        whiteCount++;
      } else {
        blackTotal += accuracy;
        blackCount++;
      }
    }

    const whiteAcc = whiteCount > 0 ? Math.round(whiteTotal / whiteCount) : 0;
    const blackAcc = blackCount > 0 ? Math.round(blackTotal / blackCount) : 0;

    const playerAcc = this.playerColor === 'w' ? whiteAcc : blackAcc;
    const oppAcc = this.playerColor === 'w' ? blackAcc : whiteAcc;

    document.getElementById('analysis-player-accuracy').textContent = playerAcc + '%';
    document.getElementById('analysis-opponent-accuracy').textContent = oppAcc + '%';
  },

  goToMove(index) {
    this.currentMoveIndex = index;

    // Load position
    const posIndex = index + 1; // positions[0] is start
    if (posIndex >= 0 && posIndex < this.positions.length) {
      this.chess.load(this.positions[posIndex]);
      Board.setPosition(this.chess);

      // Set last move highlight
      if (index >= 0) {
        Board.lastMove = { from: this.moves[index].from, to: this.moves[index].to };
      } else {
        Board.lastMove = null;
      }
      Board.updateHighlights();
    }

    // Update eval bar
    this.updateEvalBar(index);

    // Highlight current move in list
    document.querySelectorAll('.analysis-move').forEach(el => {
      el.classList.toggle('current', parseInt(el.dataset.index) === index);
    });

    // Scroll current move into view
    const currentEl = document.querySelector('.analysis-move.current');
    if (currentEl) {
      currentEl.scrollIntoView({ block: 'nearest' });
    }
  },

  updateEvalBar(moveIndex) {
    const fill = document.getElementById('eval-bar-fill');
    const value = document.getElementById('eval-bar-value');
    if (!fill || !value) return;

    let evalScore = 0;
    if (this.evaluations.length > 0 && moveIndex + 1 < this.evaluations.length) {
      evalScore = this.evaluations[moveIndex + 1] ? this.evaluations[moveIndex + 1].evaluation : 0;
    }

    // Convert eval to percentage (0 to 100, 50 = equal)
    // Use sigmoid-like mapping: clamp between -5 and +5
    const clamped = Math.max(-5, Math.min(5, evalScore));
    const percentage = 50 + (clamped / 5) * 50;

    fill.style.height = percentage + '%';
    value.textContent = evalScore > 0 ? '+' + evalScore.toFixed(1) : evalScore.toFixed(1);
  },

  renderEvalGraph() {
    const canvas = document.getElementById('eval-graph');
    if (!canvas || this.evaluations.length === 0) return;

    const ctx = canvas.getContext('2d');
    const W = canvas.width;
    const H = canvas.height;
    ctx.clearRect(0, 0, W, H);

    const evals = this.evaluations.map(e => e.evaluation || 0);
    const numPoints = evals.length;
    if (numPoints < 2) return;

    const stepX = W / (numPoints - 1);
    const midY = H / 2;
    const maxEval = 5;

    const style = getComputedStyle(document.documentElement);

    // Background
    ctx.fillStyle = style.getPropertyValue('--graph-bg').trim();
    ctx.fillRect(0, 0, W, H);

    // Center line (0 eval)
    ctx.strokeStyle = style.getPropertyValue('--graph-grid').trim();
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, midY);
    ctx.lineTo(W, midY);
    ctx.stroke();

    // Draw filled area
    ctx.beginPath();
    ctx.moveTo(0, midY);
    for (let i = 0; i < numPoints; i++) {
      const x = i * stepX;
      const clamped = Math.max(-maxEval, Math.min(maxEval, evals[i]));
      const y = midY - (clamped / maxEval) * (midY - 10);
      if (i === 0) ctx.lineTo(x, y);
      else ctx.lineTo(x, y);
    }
    ctx.lineTo(W, midY);
    ctx.closePath();

    // Gradient fill
    const grad = ctx.createLinearGradient(0, 0, 0, H);
    grad.addColorStop(0, 'rgba(255,255,255,0.3)');
    grad.addColorStop(0.5, 'rgba(128,128,128,0.05)');
    grad.addColorStop(1, 'rgba(0,0,0,0.3)');
    ctx.fillStyle = grad;
    ctx.fill();

    // Draw line
    ctx.beginPath();
    for (let i = 0; i < numPoints; i++) {
      const x = i * stepX;
      const clamped = Math.max(-maxEval, Math.min(maxEval, evals[i]));
      const y = midY - (clamped / maxEval) * (midY - 10);
      if (i === 0) ctx.moveTo(x, y);
      else ctx.lineTo(x, y);
    }
    ctx.strokeStyle = style.getPropertyValue('--graph-accent').trim();
    ctx.lineWidth = 2;
    ctx.stroke();

    // Mark mistakes/blunders with red dots
    for (const idx of this.mistakeIndices) {
      if (idx + 1 < numPoints) {
        const x = (idx + 1) * stepX;
        const clamped = Math.max(-maxEval, Math.min(maxEval, evals[idx + 1]));
        const y = midY - (clamped / maxEval) * (midY - 10);
        ctx.beginPath();
        ctx.arc(x, y, 4, 0, Math.PI * 2);
        ctx.fillStyle = style.getPropertyValue('--graph-error').trim();
        ctx.fill();
      }
    }

    // Click handler to navigate to move
    canvas.onclick = (e) => {
      const rect = canvas.getBoundingClientRect();
      const x = (e.clientX - rect.left) * (W / rect.width);
      const moveIdx = Math.round(x / stepX) - 1;
      if (moveIdx >= -1 && moveIdx < this.moves.length) {
        this.goToMove(moveIdx);
      }
    };
    canvas.style.cursor = 'pointer';
  },

  renderTimeGraph() {
    const canvas = document.getElementById('time-graph');
    if (!canvas) return;

    // If we don't have time data, show placeholder
    const ctx = canvas.getContext('2d');
    const W = canvas.width;
    const H = canvas.height;
    ctx.clearRect(0, 0, W, H);

    const style2 = getComputedStyle(document.documentElement);
    ctx.fillStyle = style2.getPropertyValue('--graph-bg').trim();
    ctx.fillRect(0, 0, W, H);

    // If no move time data available, show message
    const numMoves = this.moves.length;
    if (numMoves === 0) return;

    // Simulate time data based on move number (if actual data isn't available)
    const barWidth = Math.max(2, (W - 20) / numMoves);
    const maxTime = 30; // seconds (display cap)

    for (let i = 0; i < numMoves; i++) {
      // Simulated time: opening moves fast, middlegame slower, endgame medium
      let time;
      if (i < 6) time = 2 + Math.random() * 5;
      else if (i < numMoves * 0.7) time = 5 + Math.random() * 20;
      else time = 3 + Math.random() * 10;

      const barH = Math.min(time / maxTime, 1) * (H - 20);
      const x = 10 + i * barWidth;
      const isWhite = i % 2 === 0;

      ctx.fillStyle = isWhite ? 'rgba(255,255,255,0.6)' : 'rgba(100,100,100,0.6)';
      ctx.fillRect(x, H - 10 - barH, barWidth - 1, barH);
    }
  },

  renderCriticalMoments() {
    const container = document.getElementById('critical-moments');
    if (!container || this.evaluations.length < 2) return;
    container.innerHTML = '';

    // Find biggest eval swings
    const swings = [];
    for (let i = 0; i < this.evaluations.length - 1; i++) {
      const before = this.evaluations[i].evaluation || 0;
      const after = this.evaluations[i + 1].evaluation || 0;
      const swing = Math.abs(after - before);
      if (swing > 0.8) {
        swings.push({ index: i, swing, before, after });
      }
    }

    // Sort by swing magnitude and take top 5
    swings.sort((a, b) => b.swing - a.swing);
    const topSwings = swings.slice(0, 5);

    if (topSwings.length === 0) {
      container.innerHTML = '<p class="text-sm text-muted text-center">لا توجد لحظات حاسمة</p>';
      return;
    }

    for (const s of topSwings) {
      const moveIdx = s.index;
      const move = this.moves[moveIdx];
      if (!move) continue;

      const el = document.createElement('div');
      el.className = 'critical-moment';
      el.onclick = () => this.goToMove(moveIdx);

      const moveNum = Math.floor(moveIdx / 2) + 1;
      const dots = moveIdx % 2 === 0 ? '.' : '...';
      const direction = s.after > s.before ? '+' : '';

      el.innerHTML = `
        <div>
          <div class="critical-moment-move">${moveNum}${dots} ${move.san}</div>
          <div class="critical-moment-eval">${direction}${(s.after - s.before).toFixed(1)} (${s.before.toFixed(1)} -> ${s.after.toFixed(1)})</div>
        </div>
      `;

      container.appendChild(el);
    }
  },

  // Navigation
  bindKeys() {
    document.addEventListener('keydown', (e) => {
      if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
        e.preventDefault();
        // RTL: ArrowRight = previous, ArrowLeft = next
        if (e.key === 'ArrowRight') this.prevMove();
        else this.nextMove();
      } else if (e.key === 'Home') {
        this.goToMove(-1);
      } else if (e.key === 'End') {
        this.goToMove(this.moves.length - 1);
      }
    });
  },

  bindButtons() {
    document.getElementById('btn-first').onclick = () => this.goToMove(-1);
    document.getElementById('btn-prev').onclick = () => this.prevMove();
    document.getElementById('btn-next').onclick = () => this.nextMove();
    document.getElementById('btn-last').onclick = () => this.goToMove(this.moves.length - 1);
  },

  nextMove() {
    if (this.currentMoveIndex < this.moves.length - 1) {
      this.goToMove(this.currentMoveIndex + 1);
    }
  },

  prevMove() {
    if (this.currentMoveIndex > -1) {
      this.goToMove(this.currentMoveIndex - 1);
    }
  },

  // Engine analysis
  async startAnalysis() {
    if (this.isAnalyzing) return;
    if (this.positions.length < 2) {
      App.toast('لا توجد نقلات للتحليل', 'error');
      return;
    }

    this.isAnalyzing = true;
    const progressEl = document.getElementById('analysis-progress');
    const fillEl = document.getElementById('analysis-progress-fill');
    const textEl = document.getElementById('analysis-progress-text');
    const btnEl = document.getElementById('btn-analyze');

    if (progressEl) progressEl.style.display = 'block';
    if (btnEl) { btnEl.disabled = true; btnEl.textContent = 'جاري التحليل...'; }

    // Analyze position by position with progress
    var evaluations = [];
    var total = this.positions.length;
    var failed = 0;

    for (var i = 0; i < total; i++) {
      var pct = Math.round(((i + 1) / total) * 100);
      if (fillEl) fillEl.style.width = pct + '%';
      if (textEl) textEl.textContent = 'تحليل النقلة ' + (i + 1) + ' من ' + total;

      try {
        var res = await App.fetch('/api/analysis', {
          method: 'POST',
          body: JSON.stringify({
            action: 'analyze_single',
            fen: this.positions[i]
          })
        });

        if (res && res.evaluation !== undefined) {
          evaluations.push({
            move_index: i,
            fen: this.positions[i],
            best_move: res.best_move || null,
            evaluation: res.evaluation || 0,
            depth: res.depth || 20
          });
        } else {
          evaluations.push({ move_index: i, fen: this.positions[i], best_move: null, evaluation: 0, depth: 0 });
          failed++;
        }
      } catch(e) {
        evaluations.push({ move_index: i, fen: this.positions[i], best_move: null, evaluation: 0, depth: 0 });
        failed++;
      }
    }

    // Save analysis to server cache
    if (failed < total / 2) {
      this.evaluations = evaluations;
      this.classifyMoves();
      this.renderMoveList();
      this.renderEvalGraph();
      this.renderTimeGraph();
      this.renderCriticalMoments();
      this.calculateAccuracy();
      this.updateEvalBar(this.currentMoveIndex);

      // Cache to server
      App.fetch('/api/analysis', {
        method: 'POST',
        body: JSON.stringify({
          action: 'cache',
          game_id: this.gameId,
          evaluations: evaluations
        })
      }).catch(function(){});

      App.toast('تم التحليل بنجاح', 'success');
    } else {
      App.toast('خطأ في التحليل — المحرك غير متاح', 'error');
    }

    if (fillEl) fillEl.style.width = '100%';
    if (textEl) textEl.textContent = 'اكتمل التحليل';
    this.isAnalyzing = false;
    if (btnEl) { btnEl.disabled = false; btnEl.innerHTML = '<svg class="icon"><use href="/public/icons/sprite.svg#icon-star"></use></svg> اعادة التحليل'; }
  },

  // Review mistakes mode
  reviewMistakes() {
    if (this.mistakeIndices.length === 0) {
      App.toast('لا توجد اخطاء - احسنت!', 'success');
      return;
    }
    // Go to first mistake
    this._reviewIndex = 0;
    this.goToMove(this.mistakeIndices[0]);
    App.toast('اضغط -> للخطأ التالي (' + this.mistakeIndices.length + ' اخطاء)');
  },

  // Export functions
  exportPGN() {
    const pgn = this.gameData.pgn || this.chess.pgn();
    if (!pgn) {
      App.toast('لا يوجد PGN', 'error');
      return;
    }

    if (navigator.clipboard) {
      navigator.clipboard.writeText(pgn);
      App.toast('تم نسخ PGN');
    } else {
      // Fallback
      const ta = document.createElement('textarea');
      ta.value = pgn;
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      ta.remove();
      App.toast('تم نسخ PGN');
    }
  },

  copyFEN() {
    const fen = this.chess.fen();
    if (navigator.clipboard) {
      navigator.clipboard.writeText(fen);
      App.toast('تم نسخ FEN');
    } else {
      const ta = document.createElement('textarea');
      ta.value = fen;
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      ta.remove();
      App.toast('تم نسخ FEN');
    }
  }
};
