/**
 * @file sliding-piece-pattern.js
 * @description Pattern for implementing sliding pieces (Rook, Bishop, Queen)
 * These pieces slide along lines until blocked
 */

import Piece from '../models/Piece.js';
import { DIRECTIONS } from '../utils/Constants.js';
import { isValidPosition } from '../utils/Helpers.js';

/**
 * @class Rook
 * @extends Piece
 * @description Example of sliding piece implementation
 *
 * Pattern applies to:
 * - Rook: DIRECTIONS.ORTHOGONAL (vertical and horizontal)
 * - Bishop: DIRECTIONS.DIAGONAL
 * - Queen: [...DIRECTIONS.ORTHOGONAL, ...DIRECTIONS.DIAGONAL]
 */
class Rook extends Piece {
  constructor(color, position) {
    super(color, position, 'rook');
  }

  /**
   * Gets all valid moves for this rook
   * Uses sliding piece pattern
   *
   * @param {Board} board - Current board state
   * @returns {Array<Object>} Array of valid positions
   */
  getValidMoves(board) {
    const moves = [];

    // Rook moves in 4 orthogonal directions
    const directions = DIRECTIONS.ORTHOGONAL;

    // For each direction, slide until blocked
    for (const direction of directions) {
      const directionMoves = this._getMovesInDirection(board, direction);
      moves.push(...directionMoves);
    }

    return moves;
  }

  /**
   * Gets all moves in a specific direction
   *
   * @private
   * @param {Board} board - Current board state
   * @param {Object} direction - Direction vector {row, col}
   * @returns {Array<Object>} Valid positions in this direction
   */
  _getMovesInDirection(board, direction) {
    const moves = [];
    const { row, col } = this.position;

    let currentRow = row + direction.row;
    let currentCol = col + direction.col;

    // Slide in direction until we hit edge or piece
    while (isValidPosition(currentRow, currentCol)) {
      const currentPos = { row: currentRow, col: currentCol };
      const piece = board.getPieceAt(currentPos);

      if (!piece) {
        // Empty square - can move here and continue
        moves.push(currentPos);
      } else if (piece.color !== this.color) {
        // Enemy piece - can capture but can't continue
        moves.push(currentPos);
        break;
      } else {
        // Friendly piece - can't move here, stop
        break;
      }

      // Continue sliding
      currentRow += direction.row;
      currentCol += direction.col;
    }

    return moves;
  }

  clone() {
    const clone = new Rook(this.color, { ...this.position });
    clone.hasMoved = this.hasMoved;
    return clone;
  }
}

/**
 * @class Bishop
 * @extends Piece
 * @description Bishop using same sliding pattern with diagonal directions
 */
class Bishop extends Piece {
  constructor(color, position) {
    super(color, position, 'bishop');
  }

  getValidMoves(board) {
    const moves = [];
    const directions = DIRECTIONS.DIAGONAL;  // Only difference from Rook!

    for (const direction of directions) {
      const directionMoves = this._getMovesInDirection(board, direction);
      moves.push(...directionMoves);
    }

    return moves;
  }

  _getMovesInDirection(board, direction) {
    // Identical to Rook implementation
    const moves = [];
    const { row, col } = this.position;

    let currentRow = row + direction.row;
    let currentCol = col + direction.col;

    while (isValidPosition(currentRow, currentCol)) {
      const currentPos = { row: currentRow, col: currentCol };
      const piece = board.getPieceAt(currentPos);

      if (!piece) {
        moves.push(currentPos);
      } else if (piece.color !== this.color) {
        moves.push(currentPos);
        break;
      } else {
        break;
      }

      currentRow += direction.row;
      currentCol += direction.col;
    }

    return moves;
  }

  clone() {
    const clone = new Bishop(this.color, { ...this.position });
    clone.hasMoved = this.hasMoved;
    return clone;
  }
}

/**
 * @class Queen
 * @extends Piece
 * @description Queen combines Rook + Bishop movements
 */
class Queen extends Piece {
  constructor(color, position) {
    super(color, position, 'queen');
  }

  getValidMoves(board) {
    const moves = [];

    // Queen moves in all 8 directions
    const directions = [...DIRECTIONS.ORTHOGONAL, ...DIRECTIONS.DIAGONAL];

    for (const direction of directions) {
      const directionMoves = this._getMovesInDirection(board, direction);
      moves.push(...directionMoves);
    }

    return moves;
  }

  _getMovesInDirection(board, direction) {
    // Identical to Rook/Bishop implementation
    const moves = [];
    const { row, col } = this.position;

    let currentRow = row + direction.row;
    let currentCol = col + direction.col;

    while (isValidPosition(currentRow, currentCol)) {
      const currentPos = { row: currentRow, col: currentCol };
      const piece = board.getPieceAt(currentPos);

      if (!piece) {
        moves.push(currentPos);
      } else if (piece.color !== this.color) {
        moves.push(currentPos);
        break;
      } else {
        break;
      }

      currentRow += direction.row;
      currentCol += direction.col;
    }

    return moves;
  }

  clone() {
    const clone = new Queen(this.color, { ...this.position });
    clone.hasMoved = this.hasMoved;
    return clone;
  }
}

/**
 * PATTERN SUMMARY:
 *
 * All sliding pieces use the same algorithm:
 * 1. Define direction vectors
 * 2. For each direction:
 *    a. Start at piece position
 *    b. Step in direction
 *    c. Check if position is valid
 *    d. If empty: add move, continue
 *    e. If enemy: add move, stop
 *    f. If friendly: stop
 *
 * OPTIMIZATION TIP:
 * Extract _getMovesInDirection to a shared utility function
 * to avoid code duplication:
 *
 * // In a SlidingPieceHelper.js file:
 * export function getSlidingMoves(piece, board, directions) {
 *   const moves = [];
 *   for (const direction of directions) {
 *     moves.push(...getMovesInDirection(piece, board, direction));
 *   }
 *   return moves;
 * }
 *
 * // Then in pieces:
 * getValidMoves(board) {
 *   return getSlidingMoves(this, board, DIRECTIONS.ORTHOGONAL);
 * }
 */

export { Rook, Bishop, Queen };
