"""Tests for safe zone combat prevention."""

import pathlib
import tempfile
from unittest.mock import AsyncMock, MagicMock

import pytest

from mudlib.combat.engine import active_encounters, get_encounter
from mudlib.entity import Mob
from mudlib.player import Player, players
from mudlib.zone import Zone
from mudlib.zones import load_zone


@pytest.fixture(autouse=True)
def clear_state():
    """Clear global state between tests."""
    players.clear()
    active_encounters.clear()
    yield
    players.clear()
    active_encounters.clear()


@pytest.fixture
def safe_zone():
    terrain = [["." for _ in range(10)] for _ in range(10)]
    return Zone(
        name="sanctuary",
        width=10,
        height=10,
        terrain=terrain,
        safe=True,
    )


@pytest.fixture
def unsafe_zone():
    terrain = [["." for _ in range(10)] for _ in range(10)]
    return Zone(
        name="wilderness",
        width=10,
        height=10,
        terrain=terrain,
        safe=False,
    )


@pytest.fixture
def mock_writer():
    writer = MagicMock()
    writer.write = MagicMock()
    writer.drain = AsyncMock()
    return writer


@pytest.fixture
def mock_reader():
    return MagicMock()


# --- Zone property tests ---


def test_zone_safe_default_false():
    """Zones are unsafe by default."""
    zone = Zone(name="test")
    assert zone.safe is False


def test_zone_safe_true():
    """Zone can be created as safe."""
    zone = Zone(name="test", safe=True)
    assert zone.safe is True


# --- TOML loading ---


def test_load_zone_safe_flag():
    """Load a zone with safe = true from TOML."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(
            """
name = "sanctuary"
description = "a peaceful place"
width = 3
height = 3
safe = true

[terrain]
rows = [
    "...",
    "...",
    "...",
]
"""
        )
        temp_path = pathlib.Path(f.name)

    try:
        zone = load_zone(temp_path)
        assert zone.safe is True
    finally:
        temp_path.unlink()


def test_load_zone_safe_default():
    """Zone without safe field defaults to False."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(
            """
name = "wilderness"
description = "dangerous lands"
width = 3
height = 3

[terrain]
rows = [
    "...",
    "...",
    "...",
]
"""
        )
        temp_path = pathlib.Path(f.name)

    try:
        zone = load_zone(temp_path)
        assert zone.safe is False
    finally:
        temp_path.unlink()


def test_tavern_is_safe():
    """The tavern zone file has safe = true."""
    project_root = pathlib.Path(__file__).resolve().parents[1]
    tavern_path = project_root / "content" / "zones" / "tavern.toml"
    zone = load_zone(tavern_path)
    assert zone.safe is True


# --- Combat prevention ---


@pytest.mark.asyncio
async def test_attack_blocked_in_safe_zone(safe_zone, mock_writer, mock_reader):
    """Attacking in a safe zone sends error message."""
    from mudlib.combat.commands import do_attack
    from mudlib.combat.moves import CombatMove

    player = Player(
        name="attacker",
        x=5,
        y=5,
        writer=mock_writer,
        reader=mock_reader,
        location=safe_zone,
    )
    safe_zone._contents.append(player)
    players["attacker"] = player

    target = Mob(
        name="goblin",
        x=5,
        y=5,
        location=safe_zone,
        pl=50,
        stamina=40,
        max_stamina=40,
    )
    safe_zone._contents.append(target)

    move = CombatMove(
        name="punch left",
        command="punch",
        variant="left",
        move_type="attack",
        stamina_cost=5,
        timing_window_ms=850,
        damage_pct=0.15,
    )

    await do_attack(player, "goblin", move)

    # Should have sent the safe zone message
    mock_writer.write.assert_called()
    written = mock_writer.write.call_args_list[0][0][0]
    assert "can't fight here" in written.lower()

    # Should NOT have started combat
    assert get_encounter(player) is None


@pytest.mark.asyncio
async def test_attack_allowed_in_unsafe_zone(unsafe_zone, mock_writer, mock_reader):
    """Attacking in an unsafe zone works normally."""
    from mudlib.combat.commands import do_attack
    from mudlib.combat.moves import CombatMove

    player = Player(
        name="fighter",
        x=5,
        y=5,
        writer=mock_writer,
        reader=mock_reader,
        location=unsafe_zone,
    )
    unsafe_zone._contents.append(player)
    players["fighter"] = player

    target = Mob(
        name="goblin",
        x=5,
        y=5,
        location=unsafe_zone,
        pl=50,
        stamina=40,
        max_stamina=40,
    )
    unsafe_zone._contents.append(target)

    move = CombatMove(
        name="punch left",
        command="punch",
        variant="left",
        move_type="attack",
        stamina_cost=5,
        timing_window_ms=850,
        damage_pct=0.15,
    )

    await do_attack(player, "goblin", move)

    # Combat SHOULD have started
    assert get_encounter(player) is not None
