import pytest
from multiplayer_crosswords.crossword import Crossword, Orientation, PlacedWord
from unittest.mock import MagicMock

class DummyWord:
    def __init__(self, word):
        self.word = word

class DummyDictionary:
    def __init__(self, words):
        self.words = words

def make_crossword(rows=5, cols=5):
    dictionary = DummyDictionary([DummyWord("HELLO"), DummyWord("WORLD")])
    return Crossword(rows, cols, dictionary)

def test_can_place_word_empty_grid_horizontal():
    cw = make_crossword()
    word = DummyWord("HELLO")
    assert cw.can_place_word(word, 0, 0, Orientation.HORIZONTAL)
    assert not cw.can_place_word(word, 0, 1, Orientation.HORIZONTAL)  # would go out of bounds

def test_can_place_word_empty_grid_vertical():
    cw = make_crossword()
    word = DummyWord("HELLO")
    assert cw.can_place_word(word, 0, 0, Orientation.VERTICAL)
    assert not cw.can_place_word(word, 1, 0, Orientation.VERTICAL)  # would go out of bounds

def test_add_word_and_grid_update():
    cw = make_crossword()
    word = DummyWord("HELLO")
    assert cw.add_word(word, 0, 0, Orientation.HORIZONTAL)
    # Check grid contents
    assert cw.grid[0][0] == "H"
    assert cw.grid[0][1] == "E"
    assert cw.grid[0][2] == "L"
    assert cw.grid[0][3] == "L"
    assert cw.grid[0][4] == "O"
    # Start and end blocks
    assert cw.grid[0][0-0][0-1] == "#" if cw._in_bounds(0, -1) else True
    assert cw.grid[0][5] == "#" if cw._in_bounds(0, 5) else True

def test_cannot_place_overlapping_different_letter():
    cw = make_crossword()
    word1 = DummyWord("HELLO")
    word2 = DummyWord("WORLD")
    assert cw.add_word(word1, 0, 0, Orientation.HORIZONTAL)
    # Try to place "WORLD" vertically overlapping 'E' with 'O'
    assert not cw.can_place_word(word2, 0, 1, Orientation.VERTICAL)

def test_can_place_overlapping_same_letter():
    cw = make_crossword()
    word1 = DummyWord("HELLO")
    word2 = DummyWord("EVE")
    assert cw.add_word(word1, 0, 0, Orientation.HORIZONTAL)
    # "EVE" vertical, E overlaps at (0,1)
    word2 = DummyWord("EVE")
    assert cw.can_place_word(word2, 0, 1, Orientation.VERTICAL)
    assert cw.add_word(word2, 0, 1, Orientation.VERTICAL)

def test_blocks_are_placed_correctly():
    cw = make_crossword()
    word = DummyWord("HI")
    assert cw.add_word(word, 2, 2, Orientation.HORIZONTAL)
    # Start block
    assert cw.grid[2][1] == "#"
    # End block
    assert cw.grid[2][4] == "#"

def test_str_representation():
    cw = make_crossword()
    word = DummyWord("HI")
    cw.add_word(word, 0, 0, Orientation.HORIZONTAL)
    s = str(cw)
    assert "HI" in s
    assert "." in s

def test_placed_words_tracking():
    cw = make_crossword()
    word = DummyWord("HI")
    cw.add_word(word, 1, 1, Orientation.VERTICAL)
    assert len(cw.placed_words) == 1
    placed = cw.placed_words[0]
    assert placed.word == word
    assert placed.row == 1
    assert placed.col == 1
    assert placed.orientation == Orientation.VERTICAL

def test_valid_hello_world_crossword():
    cw = make_crossword()
    assert cw.add_word(DummyWord("HELLO"), 1, 0, Orientation.HORIZONTAL)
    assert cw.add_word(DummyWord("WORLD"), 0, 4, Orientation.VERTICAL)
    assert str(cw).count('H') == 1
    assert str(cw).count('E') == 1
    assert str(cw).count('L') == 3
    assert str(cw).count('O') == 1
    assert str(cw).count('W') == 1
    assert str(cw).count('R') == 1
    assert str(cw).count('D') == 1