"""Tests for the spawn command."""

from unittest.mock import AsyncMock, MagicMock

import pytest

from mudlib.commands.spawn import cmd_spawn
from mudlib.mobs import MobTemplate, mob_templates, mobs
from mudlib.player import Player, players
from mudlib.zone import Zone


@pytest.fixture(autouse=True)
def clear_state():
    """Clear mobs, templates, and players."""
    mobs.clear()
    mob_templates.clear()
    players.clear()
    yield
    mobs.clear()
    mob_templates.clear()
    players.clear()


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


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


@pytest.fixture
def test_zone():
    """Create a test zone for spawning."""
    terrain = [["." for _ in range(256)] for _ in range(256)]
    zone = Zone(
        name="testzone",
        width=256,
        height=256,
        toroidal=True,
        terrain=terrain,
        impassable=set(),
    )
    return zone


@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
    p = Player(name="Goku", x=10, y=20, reader=mock_reader, writer=mock_writer)
    p.location = test_zone
    test_zone._contents.append(p)
    players[p.name] = p
    return p


@pytest.fixture
def goblin_template():
    t = MobTemplate(
        name="goblin",
        description="a snarling goblin",
        pl=50.0,
        stamina=40.0,
        max_stamina=40.0,
        moves=["punch left"],
    )
    mob_templates["goblin"] = t
    return t


@pytest.mark.asyncio
async def test_spawn_valid_mob(player, goblin_template):
    """Spawn creates a mob at the player's position."""
    await cmd_spawn(player, "goblin")

    assert len(mobs) == 1
    mob = mobs[0]
    assert mob.name == "goblin"
    assert mob.x == player.x
    assert mob.y == player.y

    messages = [call[0][0] for call in player.writer.write.call_args_list]
    assert any("goblin" in msg.lower() and "appears" in msg.lower() for msg in messages)


@pytest.mark.asyncio
async def test_spawn_invalid_type(player, goblin_template):
    """Spawn with unknown type shows available mobs."""
    await cmd_spawn(player, "dragon")

    assert len(mobs) == 0
    messages = [call[0][0] for call in player.writer.write.call_args_list]
    assert any("unknown" in msg.lower() for msg in messages)
    assert any("goblin" in msg.lower() for msg in messages)


@pytest.mark.asyncio
async def test_spawn_no_args(player, goblin_template):
    """Spawn with no args shows usage."""
    await cmd_spawn(player, "")

    assert len(mobs) == 0
    messages = [call[0][0] for call in player.writer.write.call_args_list]
    assert any("usage" in msg.lower() for msg in messages)
