/**
 * @jest-environment jsdom
 */

import { Queen } from '../../../js/pieces/Queen.js';
import { Board } from '../../../js/game/Board.js';

describe('Queen', () => {
  let board;

  beforeEach(() => {
    board = new Board();
    board.clear();
  });

  describe('Combined Movement', () => {
    test('queen in center can move to 27 squares', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const moves = queen.getValidMoves(board);

      // 7 horizontal + 7 vertical + 13 diagonal = 27 squares
      expect(moves).toHaveLength(27);
    });

    test('queen can move like rook (straight lines)', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const moves = queen.getValidMoves(board);

      // Should have all horizontal moves
      for (let col = 0; col < 8; col++) {
        if (col !== 4) {
          expect(moves).toContainEqual({ row: 4, col });
        }
      }

      // Should have all vertical moves
      for (let row = 0; row < 8; row++) {
        if (row !== 4) {
          expect(moves).toContainEqual({ row, col: 4 });
        }
      }
    });

    test('queen can move like bishop (diagonals)', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const moves = queen.getValidMoves(board);

      // Should have diagonal moves
      const diagonalMoves = moves.filter(move => {
        const rowDiff = Math.abs(move.row - 4);
        const colDiff = Math.abs(move.col - 4);
        return rowDiff === colDiff && rowDiff > 0;
      });

      expect(diagonalMoves.length).toBe(13);
    });

    test('queen in corner has 21 moves', () => {
      const queen = new Queen('white', { row: 0, col: 0 });
      board.setPiece(0, 0, queen);

      const moves = queen.getValidMoves(board);

      // 7 right + 7 down + 7 diagonal = 21
      expect(moves).toHaveLength(21);
    });
  });

  describe('Blocking and Obstacles', () => {
    test('queen blocked by own pieces', () => {
      const queen = new Queen('white', { row: 4, col: 4 });

      board.setPiece(4, 4, queen);
      board.setPiece(4, 6, { type: 'pawn', color: 'white', position: { row: 4, col: 6 } });
      board.setPiece(2, 4, { type: 'knight', color: 'white', position: { row: 2, col: 4 } });
      board.setPiece(2, 2, { type: 'bishop', color: 'white', position: { row: 2, col: 2 } });

      const moves = queen.getValidMoves(board);

      // Horizontal: can't reach (4,6) or beyond
      expect(moves).toContainEqual({ row: 4, col: 5 });
      expect(moves).not.toContainEqual({ row: 4, col: 6 });

      // Vertical: can't reach (2,4) or beyond
      expect(moves).toContainEqual({ row: 3, col: 4 });
      expect(moves).not.toContainEqual({ row: 2, col: 4 });

      // Diagonal: can't reach (2,2) or beyond
      expect(moves).toContainEqual({ row: 3, col: 3 });
      expect(moves).not.toContainEqual({ row: 2, col: 2 });
    });

    test('queen can capture opponent pieces but not jump', () => {
      const queen = new Queen('white', { row: 4, col: 4 });

      board.setPiece(4, 4, queen);
      board.setPiece(4, 6, { type: 'pawn', color: 'black', position: { row: 4, col: 6 } });
      board.setPiece(2, 4, { type: 'knight', color: 'black', position: { row: 2, col: 4 } });
      board.setPiece(2, 2, { type: 'bishop', color: 'black', position: { row: 2, col: 2 } });

      const moves = queen.getValidMoves(board);

      // Can capture all three pieces
      expect(moves).toContainEqual({ row: 4, col: 6 });
      expect(moves).toContainEqual({ row: 2, col: 4 });
      expect(moves).toContainEqual({ row: 2, col: 2 });

      // But can't move beyond them
      expect(moves).not.toContainEqual({ row: 4, col: 7 });
      expect(moves).not.toContainEqual({ row: 1, col: 4 });
      expect(moves).not.toContainEqual({ row: 1, col: 1 });
    });
  });

  describe('Power and Range', () => {
    test('queen is most powerful piece in terms of mobility', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const queenMoves = queen.getValidMoves(board);

      // Compare with other pieces from same position
      const otherPieces = [
        { name: 'rook', moves: 14 },
        { name: 'bishop', moves: 13 },
        { name: 'knight', moves: 8 },
        { name: 'king', moves: 8 }
      ];

      otherPieces.forEach(piece => {
        expect(queenMoves.length).toBeGreaterThan(piece.moves);
      });
    });

    test('queen can control maximum squares from center', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const moves = queen.getValidMoves(board);

      // All 8 directions should have moves
      const directions = {
        north: moves.some(m => m.row < 4 && m.col === 4),
        south: moves.some(m => m.row > 4 && m.col === 4),
        east: moves.some(m => m.row === 4 && m.col > 4),
        west: moves.some(m => m.row === 4 && m.col < 4),
        northeast: moves.some(m => m.row < 4 && m.col > 4),
        northwest: moves.some(m => m.row < 4 && m.col < 4),
        southeast: moves.some(m => m.row > 4 && m.col > 4),
        southwest: moves.some(m => m.row > 4 && m.col < 4)
      };

      Object.values(directions).forEach(hasMove => {
        expect(hasMove).toBe(true);
      });
    });
  });

  describe('Tactical Patterns', () => {
    test('queen can pin pieces', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      const blackRook = { type: 'rook', color: 'black', position: { row: 4, col: 6 } };
      const blackKing = { type: 'king', color: 'black', position: { row: 4, col: 7 } };

      board.setPiece(4, 4, queen);
      board.setPiece(4, 6, blackRook);
      board.setPiece(4, 7, blackKing);

      const moves = queen.getValidMoves(board);

      // Queen attacks rook (which would expose king if moved)
      expect(moves).toContainEqual({ row: 4, col: 6 });
    });

    test('queen can fork multiple pieces', () => {
      const queen = new Queen('white', { row: 4, col: 4 });

      board.setPiece(4, 4, queen);
      board.setPiece(2, 4, { type: 'rook', color: 'black', position: { row: 2, col: 4 } });
      board.setPiece(4, 7, { type: 'knight', color: 'black', position: { row: 4, col: 7 } });
      board.setPiece(6, 6, { type: 'bishop', color: 'black', position: { row: 6, col: 6 } });

      const moves = queen.getValidMoves(board);

      // Queen attacks all three pieces simultaneously
      expect(moves).toContainEqual({ row: 2, col: 4 });
      expect(moves).toContainEqual({ row: 4, col: 7 });
      expect(moves).toContainEqual({ row: 6, col: 6 });
    });
  });

  describe('Board Boundaries', () => {
    test('queen respects board edges', () => {
      const queen = new Queen('white', { row: 4, col: 4 });
      board.setPiece(4, 4, queen);

      const moves = queen.getValidMoves(board);

      moves.forEach(move => {
        expect(move.row).toBeGreaterThanOrEqual(0);
        expect(move.row).toBeLessThan(8);
        expect(move.col).toBeGreaterThanOrEqual(0);
        expect(move.col).toBeLessThan(8);
      });
    });

    test('queen from all positions stays in bounds', () => {
      for (let row = 0; row < 8; row++) {
        for (let col = 0; col < 8; col++) {
          board.clear();
          const queen = new Queen('white', { row, col });
          board.setPiece(row, col, queen);

          const moves = queen.getValidMoves(board);

          moves.forEach(move => {
            expect(board.isInBounds(move.row, move.col)).toBe(true);
          });
        }
      }
    });
  });

  describe('Initial Position', () => {
    test('queens on initial board have no moves', () => {
      board = new Board();
      board.setupInitialPosition();

      const whiteQueen = board.getPiece(7, 3);
      const blackQueen = board.getPiece(0, 3);

      expect(whiteQueen.type).toBe('queen');
      expect(blackQueen.type).toBe('queen');

      // Both queens blocked by pawns
      expect(whiteQueen.getValidMoves(board)).toHaveLength(0);
      expect(blackQueen.getValidMoves(board)).toHaveLength(0);
    });

    test('queen mobility increases as game progresses', () => {
      board = new Board();
      board.setupInitialPosition();

      const whiteQueen = board.getPiece(7, 3);
      const initialMoves = whiteQueen.getValidMoves(board);
      expect(initialMoves).toHaveLength(0);

      // Open up position
      board.movePiece(6, 3, 4, 3); // d2-d4
      board.movePiece(6, 4, 4, 4); // e2-e4

      const laterMoves = whiteQueen.getValidMoves(board);
      expect(laterMoves.length).toBeGreaterThan(initialMoves.length);
    });
  });

  describe('Value and Importance', () => {
    test('losing queen is significant disadvantage', () => {
      // Queen is worth about 9 points (rook=5, bishop=3, knight=3, pawn=1)
      const queen = new Queen('white', { row: 4, col: 4 });
      expect(queen.value).toBe(9);
    });

    test('queen trades should be carefully considered', () => {
      const whiteQueen = new Queen('white', { row: 4, col: 4 });
      const blackQueen = { type: 'queen', color: 'black', position: { row: 4, col: 6 }, value: 9 };

      board.setPiece(4, 4, whiteQueen);
      board.setPiece(4, 6, blackQueen);

      const moves = whiteQueen.getValidMoves(board);

      // Can capture black queen
      expect(moves).toContainEqual({ row: 4, col: 6 });

      // Equal trade (both queens)
      expect(whiteQueen.value).toBe(blackQueen.value);
    });
  });
});
