"""
Unit tests for Stats dataclass.

Tests computed properties, serialization, and basic operations.
"""

import pytest
from app.models.stats import Stats


def test_stats_default_values():
    """Test that Stats initializes with default values."""
    stats = Stats()

    assert stats.strength == 10
    assert stats.dexterity == 10
    assert stats.constitution == 10
    assert stats.intelligence == 10
    assert stats.wisdom == 10
    assert stats.charisma == 10


def test_stats_custom_values():
    """Test creating Stats with custom values."""
    stats = Stats(
        strength=15,
        dexterity=12,
        constitution=14,
        intelligence=8,
        wisdom=10,
        charisma=11,
    )

    assert stats.strength == 15
    assert stats.dexterity == 12
    assert stats.constitution == 14
    assert stats.intelligence == 8
    assert stats.wisdom == 10
    assert stats.charisma == 11


def test_hit_points_calculation():
    """Test HP calculation: 10 + (constitution × 2)."""
    stats = Stats(constitution=10)
    assert stats.hit_points == 30  # 10 + (10 × 2)

    stats = Stats(constitution=15)
    assert stats.hit_points == 40  # 10 + (15 × 2)

    stats = Stats(constitution=20)
    assert stats.hit_points == 50  # 10 + (20 × 2)


def test_mana_points_calculation():
    """Test MP calculation: 10 + (intelligence × 2)."""
    stats = Stats(intelligence=10)
    assert stats.mana_points == 30  # 10 + (10 × 2)

    stats = Stats(intelligence=15)
    assert stats.mana_points == 40  # 10 + (15 × 2)

    stats = Stats(intelligence=8)
    assert stats.mana_points == 26  # 10 + (8 × 2)


def test_defense_calculation():
    """Test defense calculation: constitution // 2."""
    stats = Stats(constitution=10)
    assert stats.defense == 5  # 10 // 2

    stats = Stats(constitution=15)
    assert stats.defense == 7  # 15 // 2

    stats = Stats(constitution=21)
    assert stats.defense == 10  # 21 // 2


def test_resistance_calculation():
    """Test resistance calculation: wisdom // 2."""
    stats = Stats(wisdom=10)
    assert stats.resistance == 5  # 10 // 2

    stats = Stats(wisdom=14)
    assert stats.resistance == 7  # 14 // 2

    stats = Stats(wisdom=9)
    assert stats.resistance == 4  # 9 // 2


def test_stats_serialization():
    """Test to_dict() serialization."""
    stats = Stats(
        strength=15,
        dexterity=12,
        constitution=14,
        intelligence=10,
        wisdom=11,
        charisma=8,
    )

    data = stats.to_dict()

    assert data["strength"] == 15
    assert data["dexterity"] == 12
    assert data["constitution"] == 14
    assert data["intelligence"] == 10
    assert data["wisdom"] == 11
    assert data["charisma"] == 8


def test_stats_deserialization():
    """Test from_dict() deserialization."""
    data = {
        "strength": 18,
        "dexterity": 14,
        "constitution": 16,
        "intelligence": 12,
        "wisdom": 10,
        "charisma": 9,
    }

    stats = Stats.from_dict(data)

    assert stats.strength == 18
    assert stats.dexterity == 14
    assert stats.constitution == 16
    assert stats.intelligence == 12
    assert stats.wisdom == 10
    assert stats.charisma == 9


def test_stats_deserialization_with_missing_values():
    """Test from_dict() with missing values (should use defaults)."""
    data = {
        "strength": 15,
        # Missing other stats
    }

    stats = Stats.from_dict(data)

    assert stats.strength == 15
    assert stats.dexterity == 10  # Default
    assert stats.constitution == 10  # Default
    assert stats.intelligence == 10  # Default
    assert stats.wisdom == 10  # Default
    assert stats.charisma == 10  # Default


def test_stats_round_trip_serialization():
    """Test that serialization and deserialization preserve data."""
    original = Stats(
        strength=20,
        dexterity=15,
        constitution=18,
        intelligence=10,
        wisdom=12,
        charisma=14,
    )

    # Serialize then deserialize
    data = original.to_dict()
    restored = Stats.from_dict(data)

    assert restored.strength == original.strength
    assert restored.dexterity == original.dexterity
    assert restored.constitution == original.constitution
    assert restored.intelligence == original.intelligence
    assert restored.wisdom == original.wisdom
    assert restored.charisma == original.charisma


def test_stats_copy():
    """Test that copy() creates an independent copy."""
    original = Stats(strength=15, dexterity=12, constitution=14)
    copy = original.copy()

    assert copy.strength == original.strength
    assert copy.dexterity == original.dexterity
    assert copy.constitution == original.constitution

    # Modify copy
    copy.strength = 20

    # Original should be unchanged
    assert original.strength == 15
    assert copy.strength == 20


def test_stats_repr():
    """Test string representation."""
    stats = Stats(strength=15, constitution=12, intelligence=10)
    repr_str = repr(stats)

    assert "STR=15" in repr_str
    assert "CON=12" in repr_str
    assert "INT=10" in repr_str
    assert "HP=" in repr_str
    assert "MP=" in repr_str
