"""Tests for prompt rendering system."""

from mudlib.caps import ClientCaps
from mudlib.combat.encounter import CombatEncounter
from mudlib.combat.engine import active_encounters
from mudlib.entity import Entity
from mudlib.player import Player
from mudlib.prompt import render_prompt


def setup_function():
    """Clear global state before each test."""
    active_encounters.clear()


def teardown_function():
    """Clear global state after each test."""
    active_encounters.clear()


def test_normal_mode_prompt():
    """Normal mode shows stamina gauge and power level."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # 50% is in 30-59% range, should be yellow
    assert result == "\033[33m<50%>\033[0m <200/100> "


def test_combat_mode_with_opponent():
    """Combat mode includes opponent name."""
    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
    )
    opponent = Entity(name="Vegeta", pl=150.0)

    encounter = CombatEncounter(attacker=player, defender=opponent)
    active_encounters.append(encounter)

    result = render_prompt(player)
    # 50% is in 30-59% range, should be yellow
    assert result == "\033[33m<50%>\033[0m <200/100> vs Vegeta > "


def test_combat_mode_as_defender():
    """Combat mode works when player is the defender."""
    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
    )
    opponent = Entity(name="Vegeta", pl=150.0)

    encounter = CombatEncounter(attacker=opponent, defender=player)
    active_encounters.append(encounter)

    result = render_prompt(player)
    # 50% is in 30-59% range, should be yellow
    assert result == "\033[33m<50%>\033[0m <200/100> vs Vegeta > "


def test_editor_mode_static_prompt():
    """Editor mode returns static prompt."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "editor"],
    )
    result = render_prompt(player)
    assert result == "editor> "


def test_if_mode_static_prompt():
    """IF mode returns minimal static prompt."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "if"],
    )
    result = render_prompt(player)
    assert result == "> "


def test_zero_stamina():
    """Zero stamina renders as 0% in red."""
    player = Player(
        name="Test",
        stamina=0.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # 0% is < 30%, should be red
    assert result == "\033[31m<0%>\033[0m <200/100> "


def test_max_stamina():
    """Full stamina renders as 100% in green."""
    player = Player(
        name="Test",
        stamina=100.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # 100% is >= 60%, should be green
    assert result == "\033[32m<100%>\033[0m <200/100> "


def test_fractional_percentage():
    """Stamina percentage rounds to integer."""
    player = Player(
        name="Test",
        stamina=33.3,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # 33% is in 30-59% range, should be yellow
    assert result == "\033[33m<33%>\033[0m <200/100> "


def test_fractional_pl():
    """Power level rounds to integer."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=199.7,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # 50% is in 30-59% range, should be yellow
    assert result == "\033[33m<50%>\033[0m <200/100> "


def test_custom_template_overrides_default():
    """Player can set custom prompt template."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="[{pl}] > ",
    )
    result = render_prompt(player)
    assert result == "[200] > "


def test_custom_template_all_variables():
    """Custom template can use all supported variables."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        max_pl=250.0,
        mode_stack=["normal"],
        prompt_template="{stamina}/{stamina_pct}% {pl}/{max_pl} > ",
    )
    result = render_prompt(player)
    # No color tags in this custom template, so no ANSI codes
    assert result == "50/50% 200/250 > "


def test_unknown_variable_left_as_is():
    """Unknown variables in template are not substituted."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="{pl} {unknown} > ",
    )
    result = render_prompt(player)
    assert result == "200 {unknown} > "


def test_opponent_var_in_normal_mode_empty():
    """Opponent variable is empty string when not in combat."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="{pl} vs {opponent} > ",
    )
    result = render_prompt(player)
    assert result == "200 vs  > "


def test_no_color_support():
    """Players with no ANSI support get tags stripped."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        caps=ClientCaps(ansi=False),
    )
    result = render_prompt(player)
    # Should have no ANSI codes, just text
    assert result == "<50%> <200/100> "
    assert "\033[" not in result


def test_stamina_gauge_green():
    """Stamina >= 60% renders green gauge."""
    player = Player(
        name="Test",
        stamina=80.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have green color code
    assert "\033[32m<80%>\033[0m" in result


def test_stamina_gauge_yellow():
    """Stamina 30-59% renders yellow gauge."""
    player = Player(
        name="Test",
        stamina=45.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have yellow color code
    assert "\033[33m<45%>\033[0m" in result


def test_stamina_gauge_red():
    """Stamina < 30% renders red gauge."""
    player = Player(
        name="Test",
        stamina=20.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have red color code
    assert "\033[31m<20%>\033[0m" in result


def test_stamina_gauge_boundary_60():
    """Stamina exactly 60% renders green."""
    player = Player(
        name="Test",
        stamina=60.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have green color code
    assert "\033[32m<60%>\033[0m" in result


def test_stamina_gauge_boundary_30():
    """Stamina exactly 30% renders yellow."""
    player = Player(
        name="Test",
        stamina=30.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have yellow color code
    assert "\033[33m<30%>\033[0m" in result


def test_stamina_gauge_boundary_29():
    """Stamina at 29% renders red."""
    player = Player(
        name="Test",
        stamina=29.5,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    # Should have red color code
    assert "\033[31m<29%>\033[0m" in result


def test_zero_max_stamina():
    """Zero max_stamina doesn't crash."""
    player = Player(
        name="Test",
        stamina=0.0,
        max_stamina=0.0,
        pl=200.0,
        mode_stack=["normal"],
    )
    result = render_prompt(player)
    assert "0%" in result


def test_name_variable():
    """Name variable substitutes player name."""
    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="{name} > ",
    )
    result = render_prompt(player)
    assert result == "Goku > "


def test_mode_variable():
    """Mode variable substitutes current mode."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
        prompt_template="[{mode}] > ",
    )
    result = render_prompt(player)
    assert result == "[combat] > "


def test_coordinates_variables():
    """X and Y variables substitute coordinates."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        x=42,
        y=13,
        prompt_template="({x},{y}) > ",
    )
    result = render_prompt(player)
    assert result == "(42,13) > "


def test_combat_state_idle():
    """Combat state is 'idle' when not in combat."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="[{combat_state}] > ",
    )
    result = render_prompt(player)
    assert result == "[idle] > "


def test_move_shows_name_when_in_combat_with_active_move():
    """Move variable shows attack name when in combat with current_move."""
    from mudlib.combat.moves import CombatMove

    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
        prompt_template="{move} > ",
    )
    opponent = Entity(name="Vegeta", pl=150.0)

    punch = CombatMove(
        name="punch right",
        move_type="attack",
        stamina_cost=5.0,
        timing_window_ms=800,
        damage_pct=0.15,
        countered_by=["dodge left"],
    )

    encounter = CombatEncounter(attacker=player, defender=opponent)
    encounter.attack(punch)
    active_encounters.append(encounter)

    result = render_prompt(player)
    assert result == "punch right > "


def test_move_empty_when_not_in_combat():
    """Move variable is empty string when not in combat."""
    player = Player(
        name="Test",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal"],
        prompt_template="{move} > ",
    )
    result = render_prompt(player)
    assert result == " > "


def test_move_empty_when_in_combat_but_no_current_move():
    """Move variable is empty when in combat but IDLE state (no current_move)."""
    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
        prompt_template="{move} > ",
    )
    opponent = Entity(name="Vegeta", pl=150.0)

    encounter = CombatEncounter(attacker=player, defender=opponent)
    active_encounters.append(encounter)

    result = render_prompt(player)
    assert result == " > "


def test_combat_state_shows_state_when_in_combat():
    """Combat state variable shows encounter state value."""
    from mudlib.combat.moves import CombatMove

    player = Player(
        name="Goku",
        stamina=50.0,
        max_stamina=100.0,
        pl=200.0,
        mode_stack=["normal", "combat"],
        prompt_template="[{combat_state}] > ",
    )
    opponent = Entity(name="Vegeta", pl=150.0)

    punch = CombatMove(
        name="punch right",
        move_type="attack",
        stamina_cost=5.0,
        timing_window_ms=800,
        damage_pct=0.15,
        countered_by=["dodge left"],
    )

    encounter = CombatEncounter(attacker=player, defender=opponent)
    encounter.attack(punch)
    active_encounters.append(encounter)

    result = render_prompt(player)
    assert result == "[telegraph] > "
