from __future__ import annotations

from blokus_gym.core.pieces import (
    STANDARD_PIECES,
    Piece,
    PieceOrientation,
    PieceSet,
    generate_orientations,
)


class TestPiece:
    def test_piece_creation(self):
        piece = Piece(name="F", squares=frozenset([(0, 0), (1, 0), (1, 1), (2, 1)]))
        assert piece.name == "F"
        assert piece.size == 4
        assert len(piece.squares) == 4

    def test_piece_size(self):
        piece = Piece(name="I4", squares=frozenset([(0, 0), (1, 0), (2, 0), (3, 0)]))
        assert piece.size == 4

    def test_standard_pieces_count(self):
        assert len(STANDARD_PIECES) == 21

    def test_standard_pieces_total_squares(self):
        total = sum(p.size for p in STANDARD_PIECES)
        assert total == 89

    def test_piece_orientations_via_pieceset(self):
        piece_set = PieceSet(STANDARD_PIECES)
        orientations = piece_set.get_orientations(0)
        assert len(orientations) > 0
        for orient in orientations:
            assert isinstance(orient, PieceOrientation)


class TestPieceSet:
    def test_piece_set_creation(self):
        piece_set = PieceSet(STANDARD_PIECES)
        assert piece_set.num_pieces == 21
        assert len(piece_set.pieces) == 21

    def test_piece_set_custom(self):
        custom = [p for p in STANDARD_PIECES if p.size <= 3]
        piece_set = PieceSet(custom)
        assert piece_set.num_pieces == len(custom)

    def test_piece_set_get_piece_id(self):
        piece_set = PieceSet(STANDARD_PIECES)
        piece_id = piece_set.get_piece_id("F5")
        assert piece_set.get_piece(piece_id).name == "F5"

    def test_piece_set_get_orientations(self):
        piece_set = PieceSet(STANDARD_PIECES)
        for i in range(piece_set.num_pieces):
            orientations = piece_set.get_orientations(i)
            assert len(orientations) > 0


class TestGenerateOrientations:
    def test_square_piece_one_orientation(self):
        piece = Piece("O4", frozenset([(0, 0), (0, 1), (1, 0), (1, 1)]))
        orientations = generate_orientations(piece)
        assert len(orientations) == 1

    def test_line_piece_two_orientations(self):
        piece = Piece("I3", frozenset([(0, 0), (1, 0), (2, 0)]))
        orientations = generate_orientations(piece)
        assert len(orientations) == 2

    def test_L_piece_four_orientations(self):
        piece = Piece("L3", frozenset([(0, 0), (0, 1), (1, 0)]))
        orientations = generate_orientations(piece)
        assert len(orientations) == 4

    def test_all_orientations_unique(self):
        piece_set = PieceSet(STANDARD_PIECES)
        for piece_id in range(piece_set.num_pieces):
            orientations = piece_set.get_orientations(piece_id)
            unique_cells = set()
            for orient in orientations:
                key = tuple(sorted(orient.squares))
                assert key not in unique_cells, f"Duplicate orientation in piece {piece_id}"
                unique_cells.add(key)
