"""Tests for help command showing unlock status for combat moves."""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from mudlib.combat.moves import CombatMove, UnlockCondition
from mudlib.commands import dispatch, help  # noqa: F401
from mudlib.player import Player, players


@pytest.fixture(autouse=True)
def clear_state():
    """Clear players before and after each test."""
    players.clear()
    yield
    players.clear()


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


@pytest.fixture
def player(mock_writer):
    return Player(name="Test", writer=mock_writer)


@pytest.fixture
def mock_move_kill_count():
    """Mock move with kill_count unlock condition."""
    return CombatMove(
        name="roundhouse",
        move_type="attack",
        stamina_cost=30.0,
        timing_window_ms=850,
        aliases=["rh"],
        description="A powerful spinning kick",
        damage_pct=0.35,
        unlock_condition=UnlockCondition(type="kill_count", threshold=5),
    )


@pytest.fixture
def mock_move_mob_kills():
    """Mock move with mob_kills unlock condition."""
    return CombatMove(
        name="goblin slayer",
        move_type="attack",
        stamina_cost=25.0,
        timing_window_ms=800,
        description="Specialized technique against goblins",
        damage_pct=0.40,
        unlock_condition=UnlockCondition(
            type="mob_kills", threshold=3, mob_name="goblin"
        ),
    )


@pytest.fixture
def mock_move_no_unlock():
    """Mock move without unlock condition."""
    return CombatMove(
        name="jab",
        move_type="attack",
        stamina_cost=10.0,
        timing_window_ms=600,
        description="A quick straight punch",
        damage_pct=0.15,
    )


@pytest.mark.asyncio
async def test_help_locked_move_shows_kill_count_requirement(
    player, mock_move_kill_count
):
    """Help for locked move shows kill count requirement."""
    player.unlocked_moves = set()

    moves = {"roundhouse": mock_move_kill_count, "rh": mock_move_kill_count}
    with patch("mudlib.combat.commands.combat_moves", moves):
        await dispatch(player, "help roundhouse")
        output = "".join([call[0][0] for call in player.writer.write.call_args_list])

        assert "LOCKED" in output or "Locked" in output
        assert "5" in output
        assert "enemies" in output.lower() or "kills" in output.lower()


@pytest.mark.asyncio
async def test_help_locked_move_shows_mob_kills_requirement(
    player, mock_move_mob_kills
):
    """Help for locked move shows mob-specific kill requirement."""
    player.unlocked_moves = set()

    moves = {"goblin slayer": mock_move_mob_kills}
    with patch("mudlib.combat.commands.combat_moves", moves):
        await dispatch(player, "help goblin slayer")
        output = "".join([call[0][0] for call in player.writer.write.call_args_list])

        assert "LOCKED" in output or "Locked" in output
        assert "3" in output
        assert "goblin" in output.lower()


@pytest.mark.asyncio
async def test_help_unlocked_move_no_lock_notice(player, mock_move_kill_count):
    """Help for unlocked move shows normal help without lock notice."""
    # Add move to unlocked_moves
    player.unlocked_moves = {"roundhouse"}

    moves = {"roundhouse": mock_move_kill_count, "rh": mock_move_kill_count}
    with patch("mudlib.combat.commands.combat_moves", moves):
        await dispatch(player, "help roundhouse")
        output = "".join([call[0][0] for call in player.writer.write.call_args_list])

        assert "LOCKED" not in output and "Locked" not in output
        assert "roundhouse" in output
        assert "A powerful spinning kick" in output


@pytest.mark.asyncio
async def test_help_move_without_unlock_condition(player, mock_move_no_unlock):
    """Help for move without unlock condition shows normal help."""
    player.unlocked_moves = set()

    with patch("mudlib.combat.commands.combat_moves", {"jab": mock_move_no_unlock}):
        await dispatch(player, "help jab")
        output = "".join([call[0][0] for call in player.writer.write.call_args_list])

        assert "LOCKED" not in output and "Locked" not in output
        assert "jab" in output
        assert "A quick straight punch" in output


@pytest.mark.asyncio
async def test_help_locked_move_via_alias(player, mock_move_kill_count):
    """Help via alias for locked move shows unlock requirement."""
    player.unlocked_moves = set()

    moves = {"roundhouse": mock_move_kill_count, "rh": mock_move_kill_count}
    with patch("mudlib.combat.commands.combat_moves", moves):
        await dispatch(player, "help rh")
        output = "".join([call[0][0] for call in player.writer.write.call_args_list])

        assert "LOCKED" in output or "Locked" in output
        assert "5" in output
