/**
 * @jest-environment jsdom
 */

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

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

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

  describe('Initialization', () => {
    test('should initialize 8x8 grid', () => {
      expect(board.grid).toHaveLength(8);
      board.grid.forEach(row => {
        expect(row).toHaveLength(8);
      });
    });

    test('should setup initial position correctly', () => {
      // Check white pieces
      expect(board.getPiece(7, 0).type).toBe('rook');
      expect(board.getPiece(7, 1).type).toBe('knight');
      expect(board.getPiece(7, 2).type).toBe('bishop');
      expect(board.getPiece(7, 3).type).toBe('queen');
      expect(board.getPiece(7, 4).type).toBe('king');
      expect(board.getPiece(7, 5).type).toBe('bishop');
      expect(board.getPiece(7, 6).type).toBe('knight');
      expect(board.getPiece(7, 7).type).toBe('rook');

      // Check white pawns
      for (let col = 0; col < 8; col++) {
        const pawn = board.getPiece(6, col);
        expect(pawn.type).toBe('pawn');
        expect(pawn.color).toBe('white');
      }

      // Check black pieces
      expect(board.getPiece(0, 0).type).toBe('rook');
      expect(board.getPiece(0, 4).type).toBe('king');
      expect(board.getPiece(0, 3).type).toBe('queen');

      // Check black pawns
      for (let col = 0; col < 8; col++) {
        const pawn = board.getPiece(1, col);
        expect(pawn.type).toBe('pawn');
        expect(pawn.color).toBe('black');
      }

      // Check empty squares
      for (let row = 2; row < 6; row++) {
        for (let col = 0; col < 8; col++) {
          expect(board.getPiece(row, col)).toBeNull();
        }
      }
    });

    test('should have all pieces in correct colors', () => {
      // White pieces on rows 6-7
      for (let col = 0; col < 8; col++) {
        expect(board.getPiece(6, col).color).toBe('white');
        expect(board.getPiece(7, col).color).toBe('white');
      }

      // Black pieces on rows 0-1
      for (let col = 0; col < 8; col++) {
        expect(board.getPiece(0, col).color).toBe('black');
        expect(board.getPiece(1, col).color).toBe('black');
      }
    });
  });

  describe('getPiece', () => {
    test('should return piece at valid position', () => {
      const piece = board.getPiece(0, 0);
      expect(piece).not.toBeNull();
      expect(piece.type).toBe('rook');
    });

    test('should return null for empty square', () => {
      const piece = board.getPiece(4, 4);
      expect(piece).toBeNull();
    });

    test('should throw error for invalid position', () => {
      expect(() => board.getPiece(-1, 0)).toThrow();
      expect(() => board.getPiece(0, 8)).toThrow();
      expect(() => board.getPiece(8, 0)).toThrow();
    });
  });

  describe('setPiece', () => {
    test('should place piece at position', () => {
      const mockPiece = { type: 'queen', color: 'white' };
      board.setPiece(4, 4, mockPiece);
      expect(board.getPiece(4, 4)).toBe(mockPiece);
    });

    test('should replace existing piece', () => {
      const oldPiece = board.getPiece(0, 0);
      const newPiece = { type: 'queen', color: 'white' };
      board.setPiece(0, 0, newPiece);
      expect(board.getPiece(0, 0)).toBe(newPiece);
      expect(board.getPiece(0, 0)).not.toBe(oldPiece);
    });

    test('should allow setting null to clear square', () => {
      board.setPiece(0, 0, null);
      expect(board.getPiece(0, 0)).toBeNull();
    });
  });

  describe('movePiece', () => {
    test('should move piece to empty square', () => {
      const piece = board.getPiece(6, 4);
      const result = board.movePiece(6, 4, 4, 4);

      expect(board.getPiece(4, 4)).toBe(piece);
      expect(board.getPiece(6, 4)).toBeNull();
      expect(result.captured).toBeNull();
    });

    test('should capture opponent piece', () => {
      const whitePawn = board.getPiece(6, 4);
      const blackPawn = board.getPiece(1, 3);
      board.setPiece(4, 3, blackPawn);

      const result = board.movePiece(6, 4, 4, 3);

      expect(board.getPiece(4, 3)).toBe(whitePawn);
      expect(result.captured).toBe(blackPawn);
    });

    test('should update piece position', () => {
      const piece = board.getPiece(6, 4);
      board.movePiece(6, 4, 4, 4);

      expect(piece.position.row).toBe(4);
      expect(piece.position.col).toBe(4);
    });

    test('should mark piece as moved', () => {
      const piece = board.getPiece(6, 4);
      expect(piece.hasMoved).toBe(false);

      board.movePiece(6, 4, 4, 4);
      expect(piece.hasMoved).toBe(true);
    });
  });

  describe('clone', () => {
    test('should create deep copy of board', () => {
      const cloned = board.clone();

      expect(cloned).not.toBe(board);
      expect(cloned.grid).not.toBe(board.grid);

      // Modify clone shouldn't affect original
      cloned.movePiece(6, 4, 4, 4);
      expect(board.getPiece(6, 4)).not.toBeNull();
      expect(board.getPiece(4, 4)).toBeNull();
    });
  });

  describe('isInBounds', () => {
    test('should return true for valid positions', () => {
      expect(board.isInBounds(0, 0)).toBe(true);
      expect(board.isInBounds(7, 7)).toBe(true);
      expect(board.isInBounds(3, 4)).toBe(true);
    });

    test('should return false for invalid positions', () => {
      expect(board.isInBounds(-1, 0)).toBe(false);
      expect(board.isInBounds(0, -1)).toBe(false);
      expect(board.isInBounds(8, 0)).toBe(false);
      expect(board.isInBounds(0, 8)).toBe(false);
      expect(board.isInBounds(10, 10)).toBe(false);
    });
  });

  describe('findKing', () => {
    test('should find white king', () => {
      const kingPos = board.findKing('white');
      expect(kingPos).toEqual({ row: 7, col: 4 });
    });

    test('should find black king', () => {
      const kingPos = board.findKing('black');
      expect(kingPos).toEqual({ row: 0, col: 4 });
    });

    test('should throw if king not found', () => {
      board.setPiece(7, 4, null); // Remove white king
      expect(() => board.findKing('white')).toThrow();
    });
  });

  describe('getAllPieces', () => {
    test('should return all pieces of given color', () => {
      const whitePieces = board.getAllPieces('white');
      expect(whitePieces).toHaveLength(16);
      whitePieces.forEach(piece => {
        expect(piece.color).toBe('white');
      });
    });

    test('should return all pieces on board', () => {
      const allPieces = board.getAllPieces();
      expect(allPieces).toHaveLength(32);
    });
  });

  describe('clear', () => {
    test('should clear all pieces from board', () => {
      board.clear();

      for (let row = 0; row < 8; row++) {
        for (let col = 0; col < 8; col++) {
          expect(board.getPiece(row, col)).toBeNull();
        }
      }
    });
  });
});
