from enum import Enum
from typing import List, Tuple, Optional
from multiplayer_crosswords.dictionary import Dictionary, Word

class Orientation(Enum):
    HORIZONTAL = 1
    VERTICAL = 2

class PlacedWord:
    def __init__(self, word: Word, row: int, col: int, orientation: Orientation):
        self.word = word
        self.row = row
        self.col = col
        self.orientation = orientation

class Crossword:
    def __init__(self, rows: int, cols: int, dictionary: Dictionary):
        self.rows = rows
        self.cols = cols
        self.grid = [['' for _ in range(cols)] for _ in range(rows)]
        self.dictionary = dictionary
        self.placed_words: List[PlacedWord] = []

    def _in_bounds(self, row: int, col: int) -> bool:
        return 0 <= row < self.rows and 0 <= col < self.cols

    def can_place_word(self, word: Word, row: int, col: int, orientation: Orientation) -> bool:
        length = len(word.word)
        dr, dc = (0, 1) if orientation == Orientation.HORIZONTAL else (1, 0)

        # Check start block
        start_r, start_c = row - dr, col - dc
        if self._in_bounds(start_r, start_c):
            if self.grid[start_r][start_c] not in ('', '#'):
                return False
            if self.grid[start_r][start_c] == '#':
                return False

        # Check end block
        end_r, end_c = row + dr * length, col + dc * length
        if self._in_bounds(end_r, end_c):
            if self.grid[end_r][end_c] not in ('', '#'):
                return False
            if self.grid[end_r][end_c] == '#':
                return False

        for i in range(length):
            r, c = row + dr * i, col + dc * i
            if not self._in_bounds(r, c):
                return False
            cell = self.grid[r][c]
            if cell == '#':
                return False
            if cell != '' and cell != word.word[i]:
                return False

        return True

    def add_word(self, word: Word, row: int, col: int, orientation: Orientation) -> bool:
        if not self.can_place_word(word, row, col, orientation):
            return False

        length = len(word.word)
        dr, dc = (0, 1) if orientation == Orientation.HORIZONTAL else (1, 0)

        # Place start block
        start_r, start_c = row - dr, col - dc
        if self._in_bounds(start_r, start_c):
            self.grid[start_r][start_c] = '#'

        # Place word
        for i in range(length):
            r, c = row + dr * i, col + dc * i
            self.grid[r][c] = word.word[i]

        # Place end block
        end_r, end_c = row + dr * length, col + dc * length
        if self._in_bounds(end_r, end_c):
            self.grid[end_r][end_c] = '#'

        self.placed_words.append(PlacedWord(word, row, col, orientation))
        return True

    def __str__(self):
        return '\n'.join(
            ''.join(cell if cell else '.' for cell in row)
            for row in self.grid
        )

if __name__ == "__main__":
    # Example usage
    dictionary = Dictionary()
    dictionary.add_word(Word("hello", ["greeting"], "easy"))
    dictionary.add_word(Word("world", ["earth"], "easy"))

    crossword = Crossword(5, 5, dictionary)
    crossword.add_word(dictionary.words[0], 1, 0, Orientation.HORIZONTAL)
    crossword.add_word(dictionary.words[1], 0, 4, Orientation.VERTICAL)

    print(crossword)