"""
Item system for equipment, consumables, and quest items.

This module defines the Item dataclass representing all types of items in the game,
including weapons, armor, consumables, and quest items.
"""

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

from app.models.enums import ItemType, DamageType
from app.models.effects import Effect


@dataclass
class Item:
    """
    Represents an item in the game (weapon, armor, consumable, or quest item).

    Items can provide passive stat bonuses when equipped, have weapon/armor stats,
    or provide effects when consumed.

    Attributes:
        item_id: Unique identifier
        name: Display name
        item_type: Category (weapon, armor, consumable, quest_item)
        description: Item lore and information
        value: Gold value for buying/selling
        is_tradeable: Whether item can be sold on marketplace
        stat_bonuses: Passive bonuses to stats when equipped
                     Example: {"strength": 5, "constitution": 3}
        effects_on_use: Effects applied when consumed (consumables only)

        Weapon-specific attributes:
        damage: Base weapon damage
        damage_type: Type of damage (physical, fire, etc.)
        crit_chance: Probability of critical hit (0.0 to 1.0)
        crit_multiplier: Damage multiplier on critical hit

        Armor-specific attributes:
        defense: Physical defense bonus
        resistance: Magical resistance bonus

        Requirements (future):
        required_level: Minimum character level to use
        required_class: Class restriction (if any)
    """

    item_id: str
    name: str
    item_type: ItemType
    description: str
    value: int = 0
    is_tradeable: bool = True

    # Passive bonuses (equipment)
    stat_bonuses: Dict[str, int] = field(default_factory=dict)

    # Active effects (consumables)
    effects_on_use: List[Effect] = field(default_factory=list)

    # Weapon-specific
    damage: int = 0
    damage_type: Optional[DamageType] = None
    crit_chance: float = 0.05  # 5% default critical hit chance
    crit_multiplier: float = 2.0  # 2x damage on critical hit

    # Armor-specific
    defense: int = 0
    resistance: int = 0

    # Requirements (future expansion)
    required_level: int = 1
    required_class: Optional[str] = None

    def is_weapon(self) -> bool:
        """Check if this item is a weapon."""
        return self.item_type == ItemType.WEAPON

    def is_armor(self) -> bool:
        """Check if this item is armor."""
        return self.item_type == ItemType.ARMOR

    def is_consumable(self) -> bool:
        """Check if this item is a consumable."""
        return self.item_type == ItemType.CONSUMABLE

    def is_quest_item(self) -> bool:
        """Check if this item is a quest item."""
        return self.item_type == ItemType.QUEST_ITEM

    def can_equip(self, character_level: int, character_class: Optional[str] = None) -> bool:
        """
        Check if a character can equip this item.

        Args:
            character_level: Character's current level
            character_class: Character's class (if class restrictions exist)

        Returns:
            True if item can be equipped, False otherwise
        """
        # Check level requirement
        if character_level < self.required_level:
            return False

        # Check class requirement
        if self.required_class and character_class != self.required_class:
            return False

        return True

    def get_total_stat_bonus(self, stat_name: str) -> int:
        """
        Get the total bonus for a specific stat from this item.

        Args:
            stat_name: Name of the stat (e.g., "strength", "intelligence")

        Returns:
            Bonus value for that stat (0 if not present)
        """
        return self.stat_bonuses.get(stat_name, 0)

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

        Returns:
            Dictionary containing all item data
        """
        data = asdict(self)
        data["item_type"] = self.item_type.value
        if self.damage_type:
            data["damage_type"] = self.damage_type.value
        data["effects_on_use"] = [effect.to_dict() for effect in self.effects_on_use]
        return data

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

        Args:
            data: Dictionary containing item data

        Returns:
            Item instance
        """
        # Convert string values back to enums
        item_type = ItemType(data["item_type"])
        damage_type = DamageType(data["damage_type"]) if data.get("damage_type") else None

        # Deserialize effects
        effects = []
        if "effects_on_use" in data and data["effects_on_use"]:
            effects = [Effect.from_dict(e) for e in data["effects_on_use"]]

        return cls(
            item_id=data["item_id"],
            name=data["name"],
            item_type=item_type,
            description=data["description"],
            value=data.get("value", 0),
            is_tradeable=data.get("is_tradeable", True),
            stat_bonuses=data.get("stat_bonuses", {}),
            effects_on_use=effects,
            damage=data.get("damage", 0),
            damage_type=damage_type,
            crit_chance=data.get("crit_chance", 0.05),
            crit_multiplier=data.get("crit_multiplier", 2.0),
            defense=data.get("defense", 0),
            resistance=data.get("resistance", 0),
            required_level=data.get("required_level", 1),
            required_class=data.get("required_class"),
        )

    def __repr__(self) -> str:
        """String representation of the item."""
        if self.is_weapon():
            return (
                f"Item({self.name}, weapon, dmg={self.damage}, "
                f"crit={self.crit_chance*100:.0f}%, value={self.value}g)"
            )
        elif self.is_armor():
            return (
                f"Item({self.name}, armor, def={self.defense}, "
                f"res={self.resistance}, value={self.value}g)"
            )
        elif self.is_consumable():
            return (
                f"Item({self.name}, consumable, "
                f"effects={len(self.effects_on_use)}, value={self.value}g)"
            )
        else:
            return f"Item({self.name}, quest_item)"
