"""Tests for player housing system."""

import tomllib

import pytest

from mudlib.housing import (
    HOME_HEIGHT,
    HOME_SPAWN_X,
    HOME_SPAWN_Y,
    HOME_WIDTH,
    _home_zone_name,
    create_home_zone,
    get_or_create_home,
    init_housing,
    load_home_zone,
    save_home_zone,
)
from mudlib.zones import get_zone, zone_registry


@pytest.fixture(autouse=True)
def _clean_zone_registry():
    """Clear zone registry between tests."""
    saved = dict(zone_registry)
    zone_registry.clear()
    yield
    zone_registry.clear()
    zone_registry.update(saved)


def test_init_housing_creates_directory(tmp_path):
    """init_housing() creates the zones directory."""
    zones_dir = tmp_path / "zones"
    assert not zones_dir.exists()

    init_housing(zones_dir)

    assert zones_dir.exists()
    assert zones_dir.is_dir()


def test_home_zone_name():
    """_home_zone_name() returns correct format."""
    assert _home_zone_name("Alice") == "home:alice"
    assert _home_zone_name("bob") == "home:bob"
    assert _home_zone_name("Charlie") == "home:charlie"


def test_create_home_zone(tmp_path):
    """create_home_zone() creates a zone with correct properties."""
    init_housing(tmp_path)

    zone = create_home_zone("Alice")

    # Check basic properties
    assert zone.name == "home:alice"
    assert zone.description == "Alice's home"
    assert zone.width == HOME_WIDTH
    assert zone.height == HOME_HEIGHT
    assert zone.toroidal is False
    assert zone.spawn_x == HOME_SPAWN_X
    assert zone.spawn_y == HOME_SPAWN_Y
    assert zone.safe is True
    assert zone.impassable == {"#", "^", "~"}

    # Check terrain dimensions
    assert len(zone.terrain) == HOME_HEIGHT
    assert all(len(row) == HOME_WIDTH for row in zone.terrain)

    # Check border is walls
    for x in range(HOME_WIDTH):
        assert zone.terrain[0][x] == "#"  # top
        assert zone.terrain[HOME_HEIGHT - 1][x] == "#"  # bottom
    for y in range(HOME_HEIGHT):
        assert zone.terrain[y][0] == "#"  # left
        assert zone.terrain[y][HOME_WIDTH - 1] == "#"  # right

    # Check interior is grass
    for y in range(1, HOME_HEIGHT - 1):
        for x in range(1, HOME_WIDTH - 1):
            assert zone.terrain[y][x] == "."

    # Check spawn point is passable
    assert zone.terrain[HOME_SPAWN_Y][HOME_SPAWN_X] == "."


def test_create_registers_zone(tmp_path):
    """create_home_zone() registers the zone."""
    init_housing(tmp_path)

    zone = create_home_zone("Bob")

    registered = get_zone("home:bob")
    assert registered is zone


def test_save_home_zone(tmp_path):
    """save_home_zone() writes a valid TOML file."""
    init_housing(tmp_path)

    create_home_zone("Charlie")
    zone_file = tmp_path / "charlie.toml"

    assert zone_file.exists()

    # Verify TOML is valid and contains expected data
    with open(zone_file, "rb") as f:
        data = tomllib.load(f)

    assert data["name"] == "home:charlie"
    assert data["description"] == "Charlie's home"
    assert data["width"] == HOME_WIDTH
    assert data["height"] == HOME_HEIGHT
    assert data["toroidal"] is False
    assert data["spawn_x"] == HOME_SPAWN_X
    assert data["spawn_y"] == HOME_SPAWN_Y
    assert data["safe"] is True

    # Check terrain
    rows = data["terrain"]["rows"]
    assert len(rows) == HOME_HEIGHT
    assert all(len(row) == HOME_WIDTH for row in rows)

    # Check impassable
    assert set(data["terrain"]["impassable"]["tiles"]) == {"#", "^", "~"}


def test_load_home_zone(tmp_path):
    """load_home_zone() reads a zone from disk."""
    init_housing(tmp_path)

    # Create and save a zone
    _ = create_home_zone("Dave")

    # Clear registry
    zone_registry.clear()

    # Load it back
    loaded = load_home_zone("Dave")

    assert loaded is not None
    assert loaded.name == "home:dave"
    assert loaded.description == "Dave's home"
    assert loaded.width == HOME_WIDTH
    assert loaded.height == HOME_HEIGHT
    assert loaded.toroidal is False
    assert loaded.spawn_x == HOME_SPAWN_X
    assert loaded.spawn_y == HOME_SPAWN_Y
    assert loaded.safe is True
    assert loaded.impassable == {"#", "^", "~"}


def test_load_registers_zone(tmp_path):
    """load_home_zone() registers the zone."""
    init_housing(tmp_path)

    create_home_zone("Eve")
    zone_registry.clear()

    loaded = load_home_zone("Eve")

    registered = get_zone("home:eve")
    assert registered is loaded


def test_load_nonexistent_returns_none(tmp_path):
    """load_home_zone() returns None if file doesn't exist."""
    init_housing(tmp_path)

    result = load_home_zone("Nobody")

    assert result is None


def test_round_trip(tmp_path):
    """Create -> save -> load produces equivalent zone."""
    init_housing(tmp_path)

    original = create_home_zone("Frank")
    zone_registry.clear()

    loaded = load_home_zone("Frank")
    assert loaded is not None

    # Compare all fields
    assert loaded.name == original.name
    assert loaded.description == original.description
    assert loaded.width == original.width
    assert loaded.height == original.height
    assert loaded.toroidal == original.toroidal
    assert loaded.spawn_x == original.spawn_x
    assert loaded.spawn_y == original.spawn_y
    assert loaded.safe == original.safe
    assert loaded.impassable == original.impassable

    # Compare terrain
    assert len(loaded.terrain) == len(original.terrain)
    for loaded_row, orig_row in zip(loaded.terrain, original.terrain, strict=True):
        assert loaded_row == orig_row


def test_get_or_create_home_creates_new(tmp_path):
    """get_or_create_home() creates a zone on first call."""
    init_housing(tmp_path)

    zone = get_or_create_home("Grace")

    assert zone.name == "home:grace"
    assert zone.description == "Grace's home"


def test_get_or_create_home_returns_existing_from_registry(tmp_path):
    """get_or_create_home() returns existing zone from registry."""
    init_housing(tmp_path)

    first = get_or_create_home("Hank")
    second = get_or_create_home("Hank")

    assert second is first


def test_get_or_create_home_loads_from_disk(tmp_path):
    """get_or_create_home() loads from disk if not in registry."""
    init_housing(tmp_path)

    create_home_zone("Iris")
    zone_registry.clear()

    loaded = get_or_create_home("Iris")

    assert loaded.name == "home:iris"


def test_case_insensitive_zone_names(tmp_path):
    """Zone names are lowercased consistently."""
    init_housing(tmp_path)

    zone1 = create_home_zone("JACK")
    zone2 = create_home_zone("Jack")
    zone3 = create_home_zone("jack")

    # All should reference the same zone name
    assert zone1.name == "home:jack"
    assert zone2.name == "home:jack"
    assert zone3.name == "home:jack"


def test_save_preserves_modifications(tmp_path):
    """save_home_zone() preserves modifications to terrain."""
    init_housing(tmp_path)

    zone = create_home_zone("Kate")

    # Modify terrain
    zone.terrain[2][2] = "~"  # add water
    zone.terrain[3][3] = "^"  # add mountain

    # Save modifications
    save_home_zone("Kate", zone)

    # Load and verify
    zone_registry.clear()
    loaded = load_home_zone("Kate")
    assert loaded is not None

    assert loaded.terrain[2][2] == "~"
    assert loaded.terrain[3][3] == "^"
