import random
from dataclasses import dataclass, field
from enum import Enum

from idlemaxx.models.items import Item


class EquipmentSlot(Enum):
    WEAPON = "weapon"
    HELMET = "helmet"
    BODY = "body"
    LEGS = "legs"
    FOOD = "food"


@dataclass
class WeaponData:
    attack_speed: float  # seconds per attack
    attack_bonus: int
    strength_bonus: int
    attack_req: int


@dataclass
class ArmorData:
    slot: EquipmentSlot
    defense_bonus: int
    defense_req: int


@dataclass
class FoodData:
    heal_amount: int


WEAPON_STATS: dict[Item, WeaponData] = {
    Item.BRONZE_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=14, strength_bonus=6, attack_req=1),
    Item.IRON_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=20, strength_bonus=12, attack_req=10),
    Item.STEEL_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=29, strength_bonus=22, attack_req=20),
    Item.MITHRIL_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=42, strength_bonus=36, attack_req=30),
    Item.ADAMANTITE_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=56, strength_bonus=50, attack_req=40),
    Item.RUNITE_SCIMITAR: WeaponData(attack_speed=2.4, attack_bonus=67, strength_bonus=62, attack_req=50),
}

ARMOR_STATS: dict[Item, ArmorData] = {
    # Bronze
    Item.BRONZE_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=6, defense_req=1),
    Item.BRONZE_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=12, defense_req=1),
    Item.BRONZE_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=11, defense_req=1),
    # Iron
    Item.IRON_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=8, defense_req=10),
    Item.IRON_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=15, defense_req=10),
    Item.IRON_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=14, defense_req=10),
    # Steel
    Item.STEEL_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=12, defense_req=20),
    Item.STEEL_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=21, defense_req=20),
    Item.STEEL_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=20, defense_req=20),
    # Mithril
    Item.MITHRIL_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=15, defense_req=30),
    Item.MITHRIL_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=26, defense_req=30),
    Item.MITHRIL_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=24, defense_req=30),
    # Adamantite
    Item.ADAMANTITE_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=20, defense_req=40),
    Item.ADAMANTITE_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=33, defense_req=40),
    Item.ADAMANTITE_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=31, defense_req=40),
    # Runite
    Item.RUNITE_HELMET: ArmorData(slot=EquipmentSlot.HELMET, defense_bonus=26, defense_req=50),
    Item.RUNITE_BODY: ArmorData(slot=EquipmentSlot.BODY, defense_bonus=41, defense_req=50),
    Item.RUNITE_LEGS: ArmorData(slot=EquipmentSlot.LEGS, defense_bonus=38, defense_req=50),
}

FOOD_STATS: dict[Item, FoodData] = {
    Item.COOKED_SHRIMP: FoodData(heal_amount=3),
    Item.COOKED_TROUT: FoodData(heal_amount=7),
    Item.COOKED_SALMON: FoodData(heal_amount=9),
    Item.COOKED_LOBSTER: FoodData(heal_amount=12),
    Item.COOKED_SWORDFISH: FoodData(heal_amount=14),
    Item.COOKED_SHARK: FoodData(heal_amount=20),
}


@dataclass
class LootEntry:
    item: Item
    chance: float  # 0.0–1.0
    min_quantity: int = 1
    max_quantity: int = 1

    def roll(self, rng: random.Random) -> int:
        """Returns quantity dropped (0 if not dropped)."""
        if rng.random() < self.chance:
            return rng.randint(self.min_quantity, self.max_quantity)
        return 0


@dataclass
class MonsterData:
    name: str
    hitpoints: int
    attack: int  # accuracy stat
    strength: int  # damage stat
    strength_bonus: int  # weapon-equivalent strength bonus
    defense: int
    attack_speed: float  # seconds per attack
    xp_melee: int  # XP pool awarded on kill
    loot_table: list[LootEntry] = field(default_factory=list)


class Monster(Enum):
    GOBLIN = MonsterData(
        name="Goblin",
        hitpoints=5,
        attack=1,
        strength=1,
        strength_bonus=0,
        defense=1,
        attack_speed=4.0,
        xp_melee=5,
        loot_table=[
            LootEntry(item=Item.BONES, chance=1.0),
            LootEntry(item=Item.BRONZE_SCIMITAR, chance=0.02),
            LootEntry(item=Item.COOKED_SHRIMP, chance=0.20),
        ],
    )
    GIANT_RAT = MonsterData(
        name="Giant Rat",
        hitpoints=10,
        attack=3,
        strength=3,
        strength_bonus=0,
        defense=3,
        attack_speed=3.5,
        xp_melee=10,
        loot_table=[
            LootEntry(item=Item.BONES, chance=1.0),
            LootEntry(item=Item.COOKED_SHRIMP, chance=0.15),
        ],
    )
    BARBARIAN = MonsterData(
        name="Barbarian",
        hitpoints=30,
        attack=8,
        strength=8,
        strength_bonus=0,
        defense=6,
        attack_speed=4.0,
        xp_melee=50,
        loot_table=[
            LootEntry(item=Item.BONES, chance=1.0),
            LootEntry(item=Item.IRON_SCIMITAR, chance=0.01),
            LootEntry(item=Item.COOKED_TROUT, chance=0.15),
            LootEntry(item=Item.COOKED_SALMON, chance=0.10),
        ],
    )
    ZOMBIE = MonsterData(
        name="Zombie",
        hitpoints=25,
        attack=6,
        strength=7,
        strength_bonus=0,
        defense=5,
        attack_speed=4.0,
        xp_melee=40,
        loot_table=[
            LootEntry(item=Item.BONES, chance=1.0),
            LootEntry(item=Item.COOKED_TROUT, chance=0.10),
        ],
    )
    SKELETON = MonsterData(
        name="Skeleton",
        hitpoints=25,
        attack=7,
        strength=6,
        strength_bonus=0,
        defense=5,
        attack_speed=3.5,
        xp_melee=40,
        loot_table=[
            LootEntry(item=Item.BONES, chance=1.0),
            LootEntry(item=Item.BRONZE_SCIMITAR, chance=0.03),
            LootEntry(item=Item.IRON_SCIMITAR, chance=0.005),
        ],
    )

    @property
    def hitpoints(self) -> int:
        return self.value.hitpoints

    @property
    def attack(self) -> int:
        return self.value.attack

    @property
    def strength(self) -> int:
        return self.value.strength

    @property
    def strength_bonus(self) -> int:
        return self.value.strength_bonus

    @property
    def defense(self) -> int:
        return self.value.defense

    @property
    def attack_speed(self) -> float:
        return self.value.attack_speed

    @property
    def xp_melee(self) -> int:
        return self.value.xp_melee

    @property
    def loot_table(self) -> list[LootEntry]:
        return self.value.loot_table


@dataclass
class CombatAreaMonsterEntry:
    monster: Monster
    weight: int


@dataclass
class CombatAreaData:
    name: str
    monsters: list[CombatAreaMonsterEntry]


class CombatArea(Enum):
    GOBLIN_CAVE = CombatAreaData(
        name="Goblin Cave",
        monsters=[
            CombatAreaMonsterEntry(monster=Monster.GOBLIN, weight=80),
            CombatAreaMonsterEntry(monster=Monster.GIANT_RAT, weight=20),
        ],
    )
    BARBARIAN_CAMP = CombatAreaData(
        name="Barbarian Camp",
        monsters=[
            CombatAreaMonsterEntry(monster=Monster.BARBARIAN, weight=70),
            CombatAreaMonsterEntry(monster=Monster.GIANT_RAT, weight=30),
        ],
    )
    DARK_DUNGEON = CombatAreaData(
        name="Dark Dungeon",
        monsters=[
            CombatAreaMonsterEntry(monster=Monster.ZOMBIE, weight=50),
            CombatAreaMonsterEntry(monster=Monster.SKELETON, weight=50),
        ],
    )

    @property
    def display_name(self) -> str:
        return self.value.name

    @property
    def monsters(self) -> list[CombatAreaMonsterEntry]:
        return self.value.monsters
