// EL3AB Game Controller PRO - Bot Play, Pro Timers, Move Stack, Sound, Post-game

const Game = {
  chess: null,
  playerColor: 'w',
  botId: null,
  gameId: null,
  isGameOver: false,
  moveHistory: [],
  rated: true,

  // Pro Timer
  timeControl: 600,
  increment: 0,
  timerMode: 'fischer', // 'fischer', 'bronstein', 'delay'
  clockWhite: 0,
  clockBlack: 0,
  clockInterval: null,
  activeClock: null,
  moveStartTime: 0,
  moveTimesWhite: [],
  moveTimesBlack: [],
  lastTickTime: 0,
  delayRemaining: 0,
  lowTimeWarned: { 30: false, 10: false, 5: false },

  // Audio context (lazy)
  audioCtx: null,

  // Move navigation
  currentMoveIndex: -1,

  // Opening book (common openings)
  openings: {
    'e4': 'King Pawn',
    'e4 e5': 'Open Game',
    'e4 e5 Nf3': 'King Knight Opening',
    'e4 e5 Nf3 Nc6': 'Four Knights Setup',
    'e4 e5 Nf3 Nc6 Bb5': 'Ruy Lopez',
    'e4 e5 Nf3 Nc6 Bc4': 'Italian Game',
    'e4 e5 Nf3 Nf6': 'Petrov Defense',
    'e4 c5': 'Sicilian Defense',
    'e4 c5 Nf3': 'Open Sicilian',
    'e4 c5 Nf3 d6': 'Sicilian Najdorf Setup',
    'e4 c5 Nf3 Nc6': 'Sicilian Classical',
    'e4 e6': 'French Defense',
    'e4 c6': 'Caro-Kann Defense',
    'e4 d5': 'Scandinavian Defense',
    'd4': 'Queen Pawn',
    'd4 d5': 'Closed Game',
    'd4 d5 c4': 'Queen\'s Gambit',
    'd4 d5 c4 e6': 'Queen\'s Gambit Declined',
    'd4 d5 c4 dxc4': 'Queen\'s Gambit Accepted',
    'd4 Nf6': 'Indian Defense',
    'd4 Nf6 c4': 'Indian Systems',
    'd4 Nf6 c4 g6': 'King\'s Indian Defense',
    'd4 Nf6 c4 e6': 'Nimzo/Queen\'s Indian',
    'd4 Nf6 c4 e6 Nc3 Bb4': 'Nimzo-Indian Defense',
    'Nf3': 'Reti Opening',
    'c4': 'English Opening',
    'c4 e5': 'Reversed Sicilian',
    'g3': 'King\'s Fianchetto',
    'e4 d6': 'Pirc Defense',
    'e4 g6': 'Modern Defense'
  },

  async start(options = {}) {
    this.playerColor = options.color || 'w';
    this.botId = options.botId || 'amina';
    this.timeControl = options.time || 600;
    this.increment = options.increment || 0;
    this.timerMode = options.timerMode || 'fischer';
    this.rated = options.rated !== false;
    this.clockWhite = this.timeControl;
    this.clockBlack = this.timeControl;
    this.isGameOver = false;
    this.moveHistory = [];
    this.activeClock = null;
    this.moveTimesWhite = [];
    this.moveTimesBlack = [];
    this.moveStartTime = 0;
    this.delayRemaining = 0;
    this.lowTimeWarned = { 30: false, 10: false, 5: false };
    this.currentMoveIndex = -1;

    this.chess = new Chess();

    Board.init('board', {
      flipped: this.playerColor === 'b',
      playerColor: this.playerColor,
      onMove: (move) => this.handlePlayerMove(move)
    });
    Board.setPosition(this.chess);
    Board.pushPosition(this.chess.fen());

    this.updateClockDisplay();
    this.updateMoveList();
    this.updateStatus();
    this.bindControls();

    const res = await App.fetch('/api/game', {
      method: 'POST',
      body: JSON.stringify({
        action: 'start',
        bot_id: this.botId,
        color: this.playerColor,
        time_control: this.timeControl,
        increment: this.increment,
        rated: this.rated
      })
    });

    if (res && res.game_id) {
      this.gameId = res.game_id;
    }

    if (this.playerColor === 'b') {
      this.startClock('w');
      this.requestBotMove();
    } else {
      this.startClock('w');
    }
  },

  bindControls() {
    const resignBtn = document.getElementById('btn-resign');
    const drawBtn = document.getElementById('btn-draw');
    const rematchBtn = document.getElementById('btn-rematch');
    const pgnBtn = document.getElementById('btn-pgn');
    const fenBtn = document.getElementById('btn-fen');
    const flipBtn = document.getElementById('btn-flip');

    if (resignBtn) resignBtn.onclick = () => this.resign();
    if (drawBtn) drawBtn.onclick = () => this.offerDraw();
    if (rematchBtn) rematchBtn.onclick = () => this.rematch();
    if (pgnBtn) pgnBtn.onclick = () => this.exportPGN();
    if (fenBtn) fenBtn.onclick = () => this.copyFEN();
    if (flipBtn) flipBtn.onclick = () => Board.flip();
  },

  handlePlayerMove(move) {
    if (this.isGameOver) return;
    if (this.chess.turn() !== this.playerColor) return;

    const result = this.chess.move({
      from: move.from,
      to: move.to,
      promotion: move.promotion || 'q'
    });

    if (!result) return;

    // Track move time
    const moveTime = this.recordMoveTime(this.playerColor);

    this.moveHistory.push(result);
    this.currentMoveIndex = this.moveHistory.length - 1;
    Board.lastMove = { from: move.from, to: move.to };
    Board.setPosition(this.chess);
    Board.pushPosition(this.chess.fen());
    this.applyIncrement(this.playerColor);
    this.switchClock();
    this.updateMoveList();
    this.updateStatus();
    this.playMoveSound(result);

    this.submitMove(result, moveTime);

    if (this.chess.game_over()) {
      this.endGame();
    } else {
      this.requestBotMove();
    }
  },

  // Called when it becomes the player's turn (after bot moves)
  checkPremove() {
    const premove = Board.tryExecutePremove();
    if (premove) {
      // Small delay so animation looks natural
      setTimeout(() => {
        this.handlePlayerMove(premove);
      }, 50);
      return true;
    }
    return false;
  },

  async requestBotMove() {
    this.showThinking(true);
    Board.setEnabled(false);
    const moves = this.chess.history();

    try {
      const res = await App.fetch('/api/game', {
        method: 'POST',
        body: JSON.stringify({
          action: 'bot_move',
          bot_id: this.botId,
          fen: this.chess.fen(),
          moves: moves.join(' '),
          wtime: Math.round(this.clockWhite * 1000),
          btime: Math.round(this.clockBlack * 1000)
        })
      });

      this.showThinking(false);

      if (res && res.move && !this.isGameOver) {
        const from = res.move.substring(0, 2);
        const to = res.move.substring(2, 4);
        const promotion = res.move.length > 4 ? res.move[4] : undefined;

        Board.animateMove(from, to, () => {
          const result = this.chess.move({ from: from, to: to, promotion: promotion });
          if (result) {
            const botColor = this.playerColor === 'w' ? 'b' : 'w';
            this.recordMoveTime(botColor);
            this.moveHistory.push(result);
            this.currentMoveIndex = this.moveHistory.length - 1;
            Board.lastMove = { from: from, to: to };
            Board.setPosition(this.chess);
            Board.pushPosition(this.chess.fen());
            this.applyIncrement(botColor);
            this.switchClock();
            this.updateMoveList();
            this.updateStatus();
            this.playMoveSound(result);

            Board.setEnabled(true);

            if (this.chess.game_over()) {
              this.endGame();
            } else {
              // Try to execute pre-move
              this.checkPremove();
            }
          }
        });
      } else {
        Board.setEnabled(true);
      }
    } catch (e) {
      this.showThinking(false);
      Board.setEnabled(true);
      App.toast('Connection error', 'error');
    }
  },

  submitMove(move, moveTime) {
    App.fetch('/api/game', {
      method: 'POST',
      body: JSON.stringify({
        action: 'move',
        game_id: this.gameId,
        move: move.san,
        fen: this.chess.fen(),
        clock_white: Math.round(this.clockWhite),
        clock_black: Math.round(this.clockBlack),
        move_time: moveTime
      })
    });
  },

  // --- Pro Timer System ---
  startClock(color) {
    this.stopClock();
    this.activeClock = color;
    this.moveStartTime = performance.now();
    this.lastTickTime = performance.now();
    this.delayRemaining = (this.timerMode === 'delay' || this.timerMode === 'bronstein') ? this.increment : 0;
    this.updateClockDisplay();

    this.clockInterval = setInterval(() => {
      const now = performance.now();
      const elapsed = (now - this.lastTickTime) / 1000;
      this.lastTickTime = now;

      if (this.timerMode === 'delay' && this.delayRemaining > 0) {
        // Simple delay: countdown delay first, then clock
        this.delayRemaining -= elapsed;
        if (this.delayRemaining < 0) {
          // Overflow into clock time
          const overflow = -this.delayRemaining;
          this.delayRemaining = 0;
          if (this.activeClock === 'w') {
            this.clockWhite -= overflow;
          } else {
            this.clockBlack -= overflow;
          }
        }
      } else if (this.timerMode === 'bronstein') {
        // Bronstein: delay is "given back" at end of move, up to increment
        if (this.activeClock === 'w') {
          this.clockWhite -= elapsed;
        } else {
          this.clockBlack -= elapsed;
        }
      } else {
        // Fischer: just decrement
        if (this.activeClock === 'w') {
          this.clockWhite -= elapsed;
        } else {
          this.clockBlack -= elapsed;
        }
      }

      // Check flag
      if (this.activeClock === 'w' && this.clockWhite <= 0) {
        this.clockWhite = 0;
        this.flagged('w');
      } else if (this.activeClock === 'b' && this.clockBlack <= 0) {
        this.clockBlack = 0;
        this.flagged('b');
      }

      // Low time warnings
      this.checkLowTimeWarning();
      this.updateClockDisplay();
    }, 50);
  },

  stopClock() {
    if (this.clockInterval) {
      clearInterval(this.clockInterval);
      this.clockInterval = null;
    }
  },

  switchClock() {
    const next = this.activeClock === 'w' ? 'b' : 'w';
    this.startClock(next);
  },

  applyIncrement(color) {
    if (this.increment <= 0) return;

    if (this.timerMode === 'fischer') {
      // Fischer: add full increment
      if (color === 'w') this.clockWhite += this.increment;
      else this.clockBlack += this.increment;
    } else if (this.timerMode === 'bronstein') {
      // Bronstein: add back time spent, up to increment
      const moveTime = (performance.now() - this.moveStartTime) / 1000;
      const bonus = Math.min(moveTime, this.increment);
      if (color === 'w') this.clockWhite += bonus;
      else this.clockBlack += bonus;
    }
    // Simple delay: no increment added (delay happens at start of move)
  },

  recordMoveTime(color) {
    const moveTime = (performance.now() - this.moveStartTime) / 1000;
    if (color === 'w') {
      this.moveTimesWhite.push(moveTime);
    } else {
      this.moveTimesBlack.push(moveTime);
    }
    return moveTime;
  },

  checkLowTimeWarning() {
    const settings = this.getSettings();
    if (settings.sound === false) return;

    const playerTime = this.playerColor === 'w' ? this.clockWhite : this.clockBlack;

    if (this.activeClock === this.playerColor) {
      if (playerTime <= 5 && !this.lowTimeWarned[5]) {
        this.lowTimeWarned[5] = true;
        this.playLowTimeSound(3);
      } else if (playerTime <= 10 && !this.lowTimeWarned[10]) {
        this.lowTimeWarned[10] = true;
        this.playLowTimeSound(2);
      } else if (playerTime <= 30 && !this.lowTimeWarned[30]) {
        this.lowTimeWarned[30] = true;
        this.playLowTimeSound(1);
      }
    }
  },

  flagged(color) {
    this.stopClock();
    const winner = color === 'w' ? 'b' : 'w';
    this.endGame('timeout', winner);
  },

  updateClockDisplay() {
    const topClock = document.getElementById('clock-top');
    const bottomClock = document.getElementById('clock-bottom');
    if (!topClock || !bottomClock) return;

    const topColor = this.playerColor === 'w' ? 'b' : 'w';
    const bottomColor = this.playerColor;

    const topTime = topColor === 'w' ? this.clockWhite : this.clockBlack;
    const bottomTime = bottomColor === 'w' ? this.clockWhite : this.clockBlack;

    topClock.textContent = this.formatTime(topTime);
    bottomClock.textContent = this.formatTime(bottomTime);

    topClock.className = 'game-clock' + (this.activeClock === topColor ? ' active' : '') + (topTime <= 10 ? ' clock-critical' : topTime <= 30 ? ' clock-urgent' : '');
    bottomClock.className = 'game-clock' + (this.activeClock === bottomColor ? ' active' : '') + (bottomTime <= 10 ? ' clock-critical' : bottomTime <= 30 ? ' clock-urgent' : '');
  },

  formatTime(seconds) {
    if (seconds <= 0) return '0:00.0';
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);

    if (seconds < 3) {
      // Show hundredths below 3s
      const hundredths = Math.floor((seconds % 1) * 100);
      return secs + '.' + hundredths.toString().padStart(2, '0');
    } else if (seconds < 10) {
      // Show tenths below 10s
      const tenths = Math.floor((seconds % 1) * 10);
      return secs + '.' + tenths;
    } else if (seconds < 60) {
      return '0:' + secs.toString().padStart(2, '0');
    }
    return mins + ':' + secs.toString().padStart(2, '0');
  },

  // --- Pro Move List ---
  updateMoveList() {
    const lists = [document.getElementById('move-list'), document.getElementById('move-list-mobile')].filter(Boolean);
    if (lists.length === 0) return;

    const history = this.chess.history();

    lists.forEach(list => {
      list.innerHTML = '';

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

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

        const moveIdx = i;
        const white = document.createElement('span');
        white.className = 'move' + (i === this.currentMoveIndex ? ' current' : '');
        white.textContent = history[i];
        white.dataset.moveIndex = i;
        white.onclick = () => this.jumpToMove(moveIdx);
        pair.appendChild(white);

        if (history[i + 1]) {
          const moveIdx2 = i + 1;
          const black = document.createElement('span');
          black.className = 'move' + (i + 1 === this.currentMoveIndex ? ' current' : '');
          black.textContent = history[i + 1];
          black.dataset.moveIndex = i + 1;
          black.onclick = () => this.jumpToMove(moveIdx2);
          pair.appendChild(black);
        }

        list.appendChild(pair);
      }

      list.scrollTop = list.scrollHeight;
    });

    this.updateOpeningName(history);
  },

  updateOpeningName(history) {
    const els = [
      document.getElementById('opening-display'),
      document.getElementById('opening-display-mobile')
    ].filter(Boolean);

    if (history.length === 0) {
      els.forEach(el => el.style.display = 'none');
      return;
    }

    let opening = '';
    const maxCheck = Math.min(history.length, 12);
    for (let len = maxCheck; len >= 1; len--) {
      const seq = history.slice(0, len).join(' ');
      if (this.openings[seq]) {
        opening = this.openings[seq];
        break;
      }
    }

    els.forEach(el => {
      if (opening) {
        el.style.display = 'flex';
        const nameEl = el.querySelector('.opening-name');
        if (nameEl) nameEl.textContent = opening;
      } else {
        el.style.display = 'none';
      }
    });
  },

  jumpToMove(index) {
    this.currentMoveIndex = index;
    // Navigate board to this position
    // positionHistory[0] is starting position, [1] is after first move, etc.
    Board.navigateTo(index + 1);
    // Re-highlight current move in list
    const list = document.getElementById('move-list');
    if (!list) return;
    const moves = list.querySelectorAll('.move');
    moves.forEach(m => m.classList.remove('current'));
    const target = list.querySelector('[data-move-index="' + index + '"]');
    if (target) target.classList.add('current');
  },

  // --- Game Status ---
  updateStatus() {
    const status = document.getElementById('game-status');
    const statusMobile = document.getElementById('game-status-mobile');
    if (!status && !statusMobile) return;

    let text = '';
    if (this.chess.in_checkmate()) {
      const winner = this.chess.turn() === 'w' ? 'b' : 'w';
      text = winner === this.playerColor ? 'كش مات - فزت!' : 'كش مات - خسرت';
    } else if (this.chess.in_check()) {
      text = 'كش!';
    } else if (this.chess.in_draw()) {
      text = 'تعادل';
    } else if (this.chess.in_stalemate()) {
      text = 'جمود - تعادل';
    } else {
      text = this.chess.turn() === this.playerColor ? 'دورك' : 'يفكر...';
    }

    if (status) status.textContent = text;
    if (statusMobile) statusMobile.textContent = text;
  },

  showThinking(show) {
    const el = document.getElementById('thinking-indicator');
    if (el) el.style.display = show ? 'flex' : 'none';
  },

  // --- End Game ---
  endGame(reason, winner) {
    if (this.isGameOver) return;
    this.isGameOver = true;
    this.stopClock();
    Board.setEnabled(false);
    Board.clearPremove();

    let title, subtitle;
    if (reason === 'timeout') {
      title = winner === this.playerColor ? 'فزت بالوقت!' : 'خسرت بالوقت';
      subtitle = 'انتهى الوقت';
    } else if (this.chess.in_checkmate()) {
      const w = this.chess.turn() === 'w' ? 'b' : 'w';
      title = w === this.playerColor ? 'فزت!' : 'خسرت';
      subtitle = 'كش مات';
    } else if (this.chess.in_stalemate()) {
      title = 'تعادل';
      subtitle = 'جمود';
    } else if (this.chess.in_draw()) {
      title = 'تعادل';
      subtitle = 'قطع غير كافية';
    } else if (reason === 'resign') {
      title = winner === this.playerColor ? 'فزت!' : 'خسرت';
      subtitle = 'استسلام';
    } else if (reason === 'draw') {
      title = 'تعادل';
      subtitle = 'باتفاق';
    } else {
      title = 'انتهت المباراة';
      subtitle = '';
    }

    this.playGameEndSound(winner === this.playerColor);
    if (winner === this.playerColor && typeof App !== 'undefined' && App.celebrate) {
      App.celebrate(title);
    }
    this.showResult(title, subtitle);

    const result = winner === this.playerColor ? 'win' : (winner ? 'loss' : 'draw');
    const pgn = this.chess.pgn();
    const history = this.chess.history();
    App.fetch('/api/game', {
      method: 'POST',
      body: JSON.stringify({
        action: 'end',
        game_id: this.gameId,
        result: result,
        reason: reason || 'checkmate',
        pgn: pgn,
        final_fen: this.chess.fen(),
        moves: history,
        move_count: history.length
      })
    }).catch(function() {});
  },

  showResult(title, subtitle) {
    const wrapper = document.querySelector('.board-wrapper');
    if (!wrapper) return;

    // Stats
    const totalMoves = this.moveHistory.length;
    const playerMoves = this.playerColor === 'w' ? this.moveTimesWhite : this.moveTimesBlack;
    const avgMoveTime = playerMoves.length > 0 ? (playerMoves.reduce((a, b) => a + b, 0) / playerMoves.length).toFixed(1) : '0';
    const totalTimeUsed = playerMoves.length > 0 ? playerMoves.reduce((a, b) => a + b, 0).toFixed(1) : '0';

    const gameId = this.gameId;
    const overlay = document.createElement('div');
    overlay.className = 'game-result';
    overlay.innerHTML = '<div class="game-result-title">' + title + '</div>' +
      '<div class="game-result-subtitle">' + subtitle + '</div>' +
      '<div class="game-result-stats">' +
        '<div class="stat-row"><span>النقلات</span><span>' + totalMoves + '</span></div>' +
        '<div class="stat-row"><span>متوسط وقت النقلة</span><span>' + avgMoveTime + 's</span></div>' +
        '<div class="stat-row"><span>اجمالي الوقت</span><span>' + totalTimeUsed + 's</span></div>' +
      '</div>' +
      '<div class="game-controls" style="margin-top:16px;display:flex;gap:8px;flex-wrap:wrap;justify-content:center;">' +
        '<button class="btn btn-gold" id="btn-analyze-result">تحليل اللعبة</button>' +
        '<button class="btn btn-cyan" id="btn-rematch-result">اعادة</button>' +
        '<button class="btn btn-ghost" onclick="window.location.href=\'/play\'">رجوع</button>' +
      '</div>';
    wrapper.appendChild(overlay);

    const analyzeBtn = document.getElementById('btn-analyze-result');
    if (analyzeBtn) {
      analyzeBtn.onclick = () => { window.location.href = '/analysis?id=' + gameId; };
    }

    const rematchResultBtn = document.getElementById('btn-rematch-result');
    if (rematchResultBtn) {
      rematchResultBtn.onclick = () => this.rematch();
    }
  },

  // --- Actions ---
  resign() {
    if (this.isGameOver) return;
    if (!confirm('Resign this game?')) return;
    const winner = this.playerColor === 'w' ? 'b' : 'w';
    this.endGame('resign', winner);
  },

  offerDraw() {
    if (this.isGameOver) return;
    if (!confirm('Offer a draw?')) return;
    // In bot games, draws are auto-accepted when position is drawn or agreed
    this.endGame('draw', null);
  },

  rematch() {
    // Remove result overlay
    const overlay = document.querySelector('.game-result');
    if (overlay) overlay.remove();

    // Restart with same settings but swap colors
    this.start({
      color: this.playerColor === 'w' ? 'b' : 'w',
      botId: this.botId,
      time: this.timeControl,
      increment: this.increment,
      timerMode: this.timerMode,
      rated: this.rated
    });
  },

  exportPGN() {
    const pgn = this.chess.pgn();
    if (!pgn) {
      App.toast('No moves to export', 'info');
      return;
    }
    if (navigator.clipboard) {
      navigator.clipboard.writeText(pgn).then(() => {
        App.toast('PGN copied to clipboard', 'success');
      }).catch(() => {
        this.fallbackCopy(pgn, 'PGN');
      });
    } else {
      this.fallbackCopy(pgn, 'PGN');
    }
  },

  copyFEN() {
    const fen = this.chess.fen();
    if (navigator.clipboard) {
      navigator.clipboard.writeText(fen).then(() => {
        App.toast('FEN copied to clipboard', 'success');
      }).catch(() => {
        this.fallbackCopy(fen, 'FEN');
      });
    } else {
      this.fallbackCopy(fen, 'FEN');
    }
  },

  fallbackCopy(text, label) {
    const ta = document.createElement('textarea');
    ta.value = text;
    ta.style.position = 'fixed';
    ta.style.opacity = '0';
    document.body.appendChild(ta);
    ta.select();
    try {
      document.execCommand('copy');
      App.toast(label + ' copied to clipboard', 'success');
    } catch (e) {
      App.toast('Could not copy ' + label, 'error');
    }
    document.body.removeChild(ta);
  },

  // --- Sound System (Web Audio API oscillator tones) ---
  getAudioCtx() {
    if (!this.audioCtx) {
      try {
        this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
      } catch (e) {
        return null;
      }
    }
    return this.audioCtx;
  },

  getSettings() {
    try {
      return JSON.parse(localStorage.getItem('el3ab_settings') || '{}');
    } catch (e) {
      return {};
    }
  },

  isSoundEnabled() {
    const settings = this.getSettings();
    return settings.sound !== false;
  },

  playTone(freq, duration, gain, type) {
    if (!this.isSoundEnabled()) return;
    const ctx = this.getAudioCtx();
    if (!ctx) return;

    try {
      const osc = ctx.createOscillator();
      const gainNode = ctx.createGain();
      osc.connect(gainNode);
      gainNode.connect(ctx.destination);

      osc.type = type || 'sine';
      osc.frequency.setValueAtTime(freq, ctx.currentTime);
      gainNode.gain.setValueAtTime(gain || 0.1, ctx.currentTime);
      gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + duration);

      osc.start(ctx.currentTime);
      osc.stop(ctx.currentTime + duration);
    } catch (e) {}
  },

  playMoveSound(move) {
    if (!this.isSoundEnabled()) return;

    if (move.san === 'O-O' || move.san === 'O-O-O') {
      // Castle sound: two quick tones
      this.playTone(500, 0.06, 0.12, 'sine');
      setTimeout(() => this.playTone(600, 0.06, 0.12, 'sine'), 70);
    } else if (move.san && move.san.includes('+')) {
      // Check sound: sharp high tone
      this.playTone(880, 0.15, 0.15, 'square');
    } else if (move.captured) {
      // Capture sound: percussive low
      this.playTone(180, 0.12, 0.18, 'sawtooth');
    } else {
      // Normal move: clean click
      this.playTone(440, 0.06, 0.1, 'sine');
    }
  },

  playGameEndSound(isWin) {
    if (!this.isSoundEnabled()) return;

    if (isWin) {
      // Ascending fanfare
      this.playTone(523, 0.15, 0.12, 'sine');
      setTimeout(() => this.playTone(659, 0.15, 0.12, 'sine'), 150);
      setTimeout(() => this.playTone(784, 0.3, 0.15, 'sine'), 300);
    } else {
      // Descending sad tones
      this.playTone(400, 0.2, 0.1, 'sine');
      setTimeout(() => this.playTone(300, 0.2, 0.1, 'sine'), 200);
      setTimeout(() => this.playTone(200, 0.4, 0.1, 'sine'), 400);
    }
  },

  playLowTimeSound(urgency) {
    if (!this.isSoundEnabled()) return;
    // urgency: 1=30s, 2=10s, 3=5s
    const freq = 600 + urgency * 200;
    const count = urgency;
    for (let i = 0; i < count; i++) {
      setTimeout(() => this.playTone(freq, 0.08, 0.15, 'square'), i * 120);
    }
  }
};
