"""Tests for combat move definitions and TOML loading."""

import pytest

from mudlib.combat.moves import CombatMove, load_move, load_moves


def test_combat_move_dataclass():
    """Test CombatMove can be instantiated with all fields."""
    move = CombatMove(
        name="punch right",
        move_type="attack",
        aliases=["pr"],
        stamina_cost=5.0,
        telegraph="{attacker} winds up a right hook!",
        timing_window_ms=800,
        damage_pct=0.15,
        countered_by=["dodge left", "parry high"],
        command="punch",
        variant="right",
    )
    assert move.name == "punch right"
    assert move.move_type == "attack"
    assert move.aliases == ["pr"]
    assert move.stamina_cost == 5.0
    assert move.telegraph == "{attacker} winds up a right hook!"
    assert move.timing_window_ms == 800
    assert move.damage_pct == 0.15
    assert move.countered_by == ["dodge left", "parry high"]
    assert move.handler is None
    assert move.command == "punch"
    assert move.variant == "right"


def test_combat_move_minimal():
    """Test CombatMove with minimal required fields."""
    move = CombatMove(
        name="test move",
        move_type="attack",
        stamina_cost=10.0,
        timing_window_ms=500,
    )
    assert move.name == "test move"
    assert move.move_type == "attack"
    assert move.aliases == []
    assert move.stamina_cost == 10.0
    assert move.telegraph == ""
    assert move.timing_window_ms == 500
    assert move.damage_pct == 0.0
    assert move.countered_by == []
    assert move.command == ""
    assert move.variant == ""


def test_load_simple_move_from_toml(tmp_path):
    """Test loading a simple combat move from TOML file."""
    toml_content = """
name = "roundhouse"
aliases = ["rh"]
move_type = "attack"
stamina_cost = 8.0
telegraph = "{attacker} spins into a roundhouse kick!"
timing_window_ms = 600
damage_pct = 0.25
countered_by = ["duck", "parry high", "parry low"]
"""
    toml_file = tmp_path / "roundhouse.toml"
    toml_file.write_text(toml_content)

    moves = load_move(toml_file)
    assert len(moves) == 1
    move = moves[0]
    assert move.name == "roundhouse"
    assert move.command == "roundhouse"
    assert move.variant == ""
    assert move.aliases == ["rh"]
    assert move.damage_pct == 0.25


def test_load_variant_move_from_toml(tmp_path):
    """Test loading a variant combat move from TOML file."""
    toml_content = """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
damage_pct = 0.15

[variants.left]
aliases = ["pl"]
telegraph = "{attacker} winds up a left hook!"
countered_by = ["dodge right", "parry high"]

[variants.right]
aliases = ["pr"]
telegraph = "{attacker} winds up a right hook!"
countered_by = ["dodge left", "parry high"]
"""
    toml_file = tmp_path / "punch.toml"
    toml_file.write_text(toml_content)

    moves = load_move(toml_file)
    assert len(moves) == 2

    by_name = {m.name: m for m in moves}
    assert "punch left" in by_name
    assert "punch right" in by_name

    left = by_name["punch left"]
    assert left.command == "punch"
    assert left.variant == "left"
    assert left.aliases == ["pl"]
    assert left.telegraph == "{attacker} winds up a left hook!"
    assert left.countered_by == ["dodge right", "parry high"]
    # Inherited from parent
    assert left.stamina_cost == 5.0
    assert left.timing_window_ms == 800
    assert left.damage_pct == 0.15

    right = by_name["punch right"]
    assert right.command == "punch"
    assert right.variant == "right"
    assert right.aliases == ["pr"]
    assert right.countered_by == ["dodge left", "parry high"]


def test_variant_inherits_shared_properties(tmp_path):
    """Test that variants inherit shared properties and can override them."""
    toml_content = """
name = "kick"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
damage_pct = 0.10

[variants.low]
aliases = ["kl"]
damage_pct = 0.08
timing_window_ms = 600

[variants.high]
aliases = ["kh"]
damage_pct = 0.15
"""
    toml_file = tmp_path / "kick.toml"
    toml_file.write_text(toml_content)

    moves = load_move(toml_file)
    by_name = {m.name: m for m in moves}

    low = by_name["kick low"]
    assert low.damage_pct == 0.08
    assert low.timing_window_ms == 600  # overridden
    assert low.stamina_cost == 5.0  # inherited

    high = by_name["kick high"]
    assert high.damage_pct == 0.15
    assert high.timing_window_ms == 800  # inherited
    assert high.stamina_cost == 5.0  # inherited


def test_load_move_with_defaults(tmp_path):
    """Test loading move with only required fields uses defaults."""
    toml_content = """
name = "basic move"
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 600
"""
    toml_file = tmp_path / "basic.toml"
    toml_file.write_text(toml_content)

    moves = load_move(toml_file)
    assert len(moves) == 1
    move = moves[0]
    assert move.name == "basic move"
    assert move.aliases == []
    assert move.telegraph == ""
    assert move.damage_pct == 0.0
    assert move.countered_by == []


def test_load_move_missing_name(tmp_path):
    """Test loading move without name raises error."""
    toml_content = """
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
"""
    toml_file = tmp_path / "bad.toml"
    toml_file.write_text(toml_content)

    with pytest.raises(ValueError, match="missing required field.*name"):
        load_move(toml_file)


def test_load_move_missing_move_type(tmp_path):
    """Test loading move without move_type raises error."""
    toml_content = """
name = "test"
stamina_cost = 5.0
timing_window_ms = 800
"""
    toml_file = tmp_path / "bad.toml"
    toml_file.write_text(toml_content)

    with pytest.raises(ValueError, match="missing required field.*move_type"):
        load_move(toml_file)


def test_load_move_missing_stamina_cost(tmp_path):
    """Test loading move without stamina_cost raises error."""
    toml_content = """
name = "test"
move_type = "attack"
timing_window_ms = 800
"""
    toml_file = tmp_path / "bad.toml"
    toml_file.write_text(toml_content)

    with pytest.raises(ValueError, match="missing required field.*stamina_cost"):
        load_move(toml_file)


def test_load_move_missing_timing_window(tmp_path):
    """Test loading move without timing_window_ms raises error."""
    toml_content = """
name = "test"
move_type = "attack"
stamina_cost = 5.0
"""
    toml_file = tmp_path / "bad.toml"
    toml_file.write_text(toml_content)

    with pytest.raises(ValueError, match="missing required field.*timing_window_ms"):
        load_move(toml_file)


def test_load_moves_from_directory(tmp_path):
    """Test loading all moves from a directory."""
    # Create a variant move
    punch_toml = tmp_path / "punch.toml"
    punch_toml.write_text(
        """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
damage_pct = 0.15

[variants.right]
aliases = ["pr"]
telegraph = "{attacker} winds up a right hook!"
countered_by = ["dodge left"]
"""
    )

    # Create a simple move
    dodge_toml = tmp_path / "dodge.toml"
    dodge_toml.write_text(
        """
name = "duck"
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 500
"""
    )

    # Create a non-TOML file that should be ignored
    other_file = tmp_path / "readme.txt"
    other_file.write_text("This should be ignored")

    moves = load_moves(tmp_path)

    # Should have entries for variant qualified names, aliases, and simple moves
    assert "punch right" in moves
    assert "pr" in moves
    assert "duck" in moves

    # Aliases should point to the same object
    assert moves["punch right"] is moves["pr"]

    # Check variant properties
    assert moves["punch right"].command == "punch"
    assert moves["punch right"].variant == "right"
    assert moves["duck"].command == "duck"
    assert moves["duck"].variant == ""


def test_load_moves_empty_directory(tmp_path):
    """Test loading from empty directory returns empty dict."""
    moves = load_moves(tmp_path)
    assert moves == {}


def test_load_moves_alias_collision(tmp_path):
    """Test that duplicate aliases are detected."""
    # Create two moves with same alias
    move1_toml = tmp_path / "move1.toml"
    move1_toml.write_text(
        """
name = "move one"
aliases = ["m"]
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
"""
    )

    move2_toml = tmp_path / "move2.toml"
    move2_toml.write_text(
        """
name = "move two"
aliases = ["m"]
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 500
"""
    )

    with pytest.raises(ValueError, match="duplicate.*alias.*m"):
        load_moves(tmp_path)


def test_load_moves_name_collision(tmp_path):
    """Test that duplicate move names are detected."""
    move1_toml = tmp_path / "move1.toml"
    move1_toml.write_text(
        """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
"""
    )

    move2_toml = tmp_path / "move2.toml"
    move2_toml.write_text(
        """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
"""
    )

    with pytest.raises(ValueError, match="duplicate.*name.*punch"):
        load_moves(tmp_path)


def test_load_moves_validates_countered_by_refs(tmp_path, caplog):
    """Test that invalid countered_by references log warnings."""
    import logging

    punch_toml = tmp_path / "punch.toml"
    punch_toml.write_text(
        """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
damage_pct = 0.15

[variants.right]
countered_by = ["dodge left", "nonexistent move"]
"""
    )

    dodge_toml = tmp_path / "dodge.toml"
    dodge_toml.write_text(
        """
name = "dodge"
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 500

[variants.left]
aliases = ["dl"]
"""
    )

    with caplog.at_level(logging.WARNING):
        moves = load_moves(tmp_path)

    # Should still load successfully
    assert "punch right" in moves
    assert "dodge left" in moves

    # Should have logged a warning about the invalid reference
    assert any("nonexistent move" in record.message for record in caplog.records)
    assert any("punch right" in record.message for record in caplog.records)


def test_load_moves_valid_countered_by_refs_no_warning(tmp_path, caplog):
    """Test that valid countered_by references don't log warnings."""
    import logging

    punch_toml = tmp_path / "punch.toml"
    punch_toml.write_text(
        """
name = "punch"
move_type = "attack"
stamina_cost = 5.0
timing_window_ms = 800
damage_pct = 0.15

[variants.right]
countered_by = ["dodge left", "parry high"]
"""
    )

    dodge_toml = tmp_path / "dodge.toml"
    dodge_toml.write_text(
        """
name = "dodge"
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 500

[variants.left]
aliases = ["dl"]
"""
    )

    parry_toml = tmp_path / "parry.toml"
    parry_toml.write_text(
        """
name = "parry"
move_type = "defense"
stamina_cost = 3.0
timing_window_ms = 500

[variants.high]
aliases = ["f"]
"""
    )

    with caplog.at_level(logging.WARNING):
        moves = load_moves(tmp_path)

    # Should load successfully
    assert "punch right" in moves
    assert "dodge left" in moves
    assert "parry high" in moves

    # Should have no warnings
    assert len(caplog.records) == 0


def test_load_content_combat_directory():
    """Test loading the actual content/combat directory."""
    from pathlib import Path

    content_dir = Path(__file__).parent.parent / "content" / "combat"
    moves = load_moves(content_dir)

    # Verify variant moves have correct structure
    assert "punch left" in moves
    assert "punch right" in moves
    assert moves["punch left"].command == "punch"
    assert moves["punch left"].variant == "left"

    assert "dodge left" in moves
    assert "dodge right" in moves
    assert moves["dodge left"].command == "dodge"

    assert "parry high" in moves
    assert "parry low" in moves
    assert moves["parry high"].command == "parry"

    # Verify simple moves
    assert "roundhouse" in moves
    assert moves["roundhouse"].command == "roundhouse"
    assert moves["roundhouse"].variant == ""

    assert "sweep" in moves
    assert "duck" in moves
    assert "jump" in moves
