"""Tests for look command target resolution."""

import pytest

from mudlib.commands.look import cmd_look
from mudlib.entity import Mob
from mudlib.player import Player
from mudlib.thing import Thing
from mudlib.zone import Zone


@pytest.fixture
def zone():
    """Create a test zone."""
    terrain = [["." for _ in range(100)] for _ in range(100)]
    return Zone(
        name="test",
        description="Test Zone",
        width=100,
        height=100,
        toroidal=False,
        terrain=terrain,
    )


@pytest.fixture
def mock_writer():
    """Create a mock writer that captures output."""
    from unittest.mock import MagicMock

    class MockWriter:
        def __init__(self):
            self.output = []
            # Mock telnet options
            self.local_option = MagicMock()
            self.remote_option = MagicMock()
            self.local_option.enabled = MagicMock(return_value=False)
            self.remote_option.enabled = MagicMock(return_value=False)

        def write(self, data):
            self.output.append(data)

        async def drain(self):
            pass

        def get_output(self):
            return "".join(self.output)

    return MockWriter()


@pytest.fixture
def player(zone, mock_writer):
    """Create a test player."""
    p = Player(
        name="TestPlayer",
        location=zone,
        x=50,
        y=50,
        writer=mock_writer,
    )
    return p


@pytest.mark.asyncio
async def test_look_finds_mob_by_exact_name(player, zone, mock_writer):
    """look goblin finds mob with exact name."""
    _mob = Mob(name="goblin", location=zone, x=50, y=50)

    await cmd_look(player, "goblin")

    output = mock_writer.get_output()
    assert "goblin" in output.lower()


@pytest.mark.asyncio
async def test_look_finds_mob_by_prefix(player, zone, mock_writer):
    """look gob prefix matches goblin."""
    _mob = Mob(name="goblin", location=zone, x=50, y=50)

    await cmd_look(player, "gob")

    output = mock_writer.get_output()
    assert "goblin" in output.lower()


@pytest.mark.asyncio
async def test_look_finds_second_mob_with_ordinal(player, zone, mock_writer):
    """look 2.goblin finds second goblin."""
    _mob1 = Mob(name="goblin", location=zone, x=50, y=50)
    _mob2 = Mob(name="goblin", location=zone, x=50, y=50)

    await cmd_look(player, "2.goblin")

    output = mock_writer.get_output()
    # Should find the second goblin
    assert "goblin" in output.lower()


@pytest.mark.asyncio
async def test_look_finds_thing_on_ground(player, zone, mock_writer):
    """look sword finds thing on ground and shows description."""
    _sword = Thing(
        name="sword",
        description="A sharp blade.",
        location=zone,
        x=50,
        y=50,
    )

    await cmd_look(player, "sword")

    output = mock_writer.get_output()
    assert "A sharp blade." in output


@pytest.mark.asyncio
async def test_look_shows_error_for_nonexistent(player, zone, mock_writer):
    """look nonexistent shows 'You don't see that here.'"""
    await cmd_look(player, "nonexistent")

    output = mock_writer.get_output()
    assert "You don't see that here." in output


@pytest.mark.asyncio
async def test_look_prioritizes_entity_over_thing(player, zone, mock_writer):
    """look target finds entity before thing with same name."""
    _mob = Mob(name="target", location=zone, x=50, y=50)
    _thing = Thing(
        name="target",
        description="A thing.",
        location=zone,
        x=50,
        y=50,
    )

    await cmd_look(player, "target")

    output = mock_writer.get_output()
    # Should show entity info (name/posture), not thing description
    assert "target" in output.lower()
    # Should not show thing description
    assert "A thing." not in output


@pytest.mark.asyncio
async def test_look_skips_dead_mobs(player, zone, mock_writer):
    """look goblin skips dead mobs."""
    _mob = Mob(name="goblin", location=zone, x=50, y=50)
    _mob.alive = False

    await cmd_look(player, "goblin")

    output = mock_writer.get_output()
    assert "You don't see that here." in output


@pytest.mark.asyncio
async def test_look_skips_self(player, zone, mock_writer):
    """look TestPlayer doesn't target the player themselves."""
    await cmd_look(player, "TestPlayer")

    output = mock_writer.get_output()
    assert "You don't see that here." in output


@pytest.mark.asyncio
async def test_look_finds_thing_in_inventory(player, zone, mock_writer):
    """look sword finds thing in inventory when not on ground."""
    _sword = Thing(
        name="sword",
        description="A sharp blade.",
        location=player,
    )

    await cmd_look(player, "sword")

    output = mock_writer.get_output()
    assert "A sharp blade." in output


@pytest.mark.asyncio
async def test_look_finds_second_thing_with_ordinal(player, zone, mock_writer):
    """look 2.sword finds second sword on ground."""
    _sword1 = Thing(
        name="sword",
        description="A rusty blade.",
        location=zone,
        x=50,
        y=50,
    )
    _sword2 = Thing(
        name="sword",
        description="A sharp blade.",
        location=zone,
        x=50,
        y=50,
    )

    await cmd_look(player, "2.sword")

    output = mock_writer.get_output()
    # Should show the second sword's description
    assert "A sharp blade." in output
    # Should not show the first sword's description
    assert "A rusty blade." not in output
