"""
Character statistics data model.

This module defines the Stats dataclass which represents a character's core
attributes and provides computed properties for derived values like HP and MP.
"""

from dataclasses import dataclass, field, asdict
from typing import Dict, Any


@dataclass
class Stats:
    """
    Character statistics representing core attributes.

    Attributes:
        strength: Physical power, affects melee damage
        dexterity: Agility and precision, affects initiative and evasion
        constitution: Endurance and health, affects HP and defense
        intelligence: Magical power, affects spell damage and MP
        wisdom: Perception and insight, affects magical resistance
        charisma: Social influence, affects NPC interactions
        luck: Fortune and fate, affects critical hits, loot, and random outcomes

    Computed Properties:
        hit_points: Maximum HP = 10 + (constitution × 2)
        mana_points: Maximum MP = 10 + (intelligence × 2)
        defense: Physical defense = constitution // 2
        resistance: Magical resistance = wisdom // 2
    """

    strength: int = 10
    dexterity: int = 10
    constitution: int = 10
    intelligence: int = 10
    wisdom: int = 10
    charisma: int = 10
    luck: int = 8

    @property
    def hit_points(self) -> int:
        """
        Calculate maximum hit points based on constitution.

        Formula: 10 + (constitution × 2)

        Returns:
            Maximum HP value
        """
        return 10 + (self.constitution * 2)

    @property
    def mana_points(self) -> int:
        """
        Calculate maximum mana points based on intelligence.

        Formula: 10 + (intelligence × 2)

        Returns:
            Maximum MP value
        """
        return 10 + (self.intelligence * 2)

    @property
    def defense(self) -> int:
        """
        Calculate physical defense from constitution.

        Formula: constitution // 2

        Returns:
            Physical defense value (damage reduction)
        """
        return self.constitution // 2

    @property
    def resistance(self) -> int:
        """
        Calculate magical resistance from wisdom.

        Formula: wisdom // 2

        Returns:
            Magical resistance value (spell damage reduction)
        """
        return self.wisdom // 2

    @property
    def crit_bonus(self) -> float:
        """
        Calculate critical hit chance bonus from luck.

        Formula: luck * 0.5% (0.005)

        This bonus is added to the weapon's base crit chance.
        The total crit chance is capped at 25% in the DamageCalculator.

        Returns:
            Crit chance bonus as a decimal (e.g., 0.04 for LUK 8)

        Examples:
            LUK 8: 0.04 (4% bonus)
            LUK 12: 0.06 (6% bonus)
        """
        return self.luck * 0.005

    @property
    def hit_bonus(self) -> float:
        """
        Calculate hit chance bonus (miss reduction) from luck.

        Formula: luck * 0.5% (0.005)

        This reduces the base 10% miss chance. The minimum miss
        chance is hard capped at 5% to prevent frustration.

        Returns:
            Miss reduction as a decimal (e.g., 0.04 for LUK 8)

        Examples:
            LUK 8: 0.04 (reduces miss from 10% to 6%)
            LUK 12: 0.06 (reduces miss from 10% to 4%, capped at 5%)
        """
        return self.luck * 0.005

    @property
    def lucky_roll_chance(self) -> float:
        """
        Calculate chance for a "lucky" high damage variance roll.

        Formula: 5% + (luck * 0.25%)

        When triggered, damage variance uses 100%-110% instead of 95%-105%.
        This gives LUK characters more frequent high damage rolls.

        Returns:
            Lucky roll chance as a decimal

        Examples:
            LUK 8: 0.07 (7% chance for lucky roll)
            LUK 12: 0.08 (8% chance for lucky roll)
        """
        return 0.05 + (self.luck * 0.0025)

    def to_dict(self) -> Dict[str, Any]:
        """
        Serialize stats to a dictionary.

        Returns:
            Dictionary containing all stat values
        """
        return asdict(self)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Stats':
        """
        Deserialize stats from a dictionary.

        Args:
            data: Dictionary containing stat values

        Returns:
            Stats instance
        """
        return cls(
            strength=data.get("strength", 10),
            dexterity=data.get("dexterity", 10),
            constitution=data.get("constitution", 10),
            intelligence=data.get("intelligence", 10),
            wisdom=data.get("wisdom", 10),
            charisma=data.get("charisma", 10),
            luck=data.get("luck", 8),
        )

    def copy(self) -> 'Stats':
        """
        Create a deep copy of this Stats instance.

        Returns:
            New Stats instance with same values
        """
        return Stats(
            strength=self.strength,
            dexterity=self.dexterity,
            constitution=self.constitution,
            intelligence=self.intelligence,
            wisdom=self.wisdom,
            charisma=self.charisma,
            luck=self.luck,
        )

    def __repr__(self) -> str:
        """String representation showing all stats and computed properties."""
        return (
            f"Stats(STR={self.strength}, DEX={self.dexterity}, "
            f"CON={self.constitution}, INT={self.intelligence}, "
            f"WIS={self.wisdom}, CHA={self.charisma}, LUK={self.luck}, "
            f"HP={self.hit_points}, MP={self.mana_points}, "
            f"DEF={self.defense}, RES={self.resistance}, "
            f"CRIT_BONUS={self.crit_bonus:.1%}, HIT_BONUS={self.hit_bonus:.1%})"
        )
