"""
FreeExile Weapon Engine & Combat Resolution Core.
Handles:
1. Attribute requirement checks.
2. Weapon damage scaling (Physique, Agility, Mind).
3. Two-Handed (+50% More Dmg) and Dual Wielding (+10% APS, +15% Block) mechanics.
4. Shield blocking and defensive barrier resolution.
5. Sect & Clan Affinity Resonance Buffs.
6. Server-authoritative 0ms Dual Weapon Auto-Swap.
"""

from typing import Dict, Optional, Tuple
from server.world.martial_types import FiveElements, MartialSect, WeaponCategory
from server.world.weapon_types import (
    WeaponClass,
    GripStyle,
    PrimalClan,
    WeaponImplicitStat,
    BaseWeaponTemplate,
    EquippedWeapon,
    WeaponSetLoadout,
    WeaponScalingResult,
    AffinityResonanceResult,
    AutoSwapResult,
    LoadoutEvaluationResult,
    DualWieldBonus,
)


class WeaponEngine:
    """Động cơ tính toán và thẩm định vũ khí phía máy chủ (Server-Authoritative)."""

    def __init__(self) -> None:
        self.dual_wield_rules = DualWieldBonus()

    def validate_requirements(self, template: BaseWeaponTemplate, char_stats: Dict[str, int]) -> bool:
        """Kiểm tra điều kiện Căn Cốt (Attributes) tối thiểu để mang vũ khí."""
        cuong_the = char_stats.get("cuong_the", 0)
        than_phap = char_stats.get("than_phap", 0)
        than_niem = char_stats.get("than_niem", 0)

        if cuong_the < template.req_physique:
            return False
        if than_phap < template.req_agility:
            return False
        if than_niem < template.req_mind:
            return False
        return True

    def calculate_weapon_damage(
        self,
        weapon: EquippedWeapon,
        char_stats: Dict[str, int],
        grip_style: GripStyle,
        offhand_weapon: Optional[EquippedWeapon] = None
    ) -> WeaponScalingResult:
        """
        Tính toán sát thương, tốc độ đánh, bạo kích và tầm với của vũ khí.
        Áp dụng scaling Căn Cốt (Str/Dex/Int) và cơ chế Two-Handed hoặc Dual-Wield.
        """
        tpl = weapon.template
        cuong_the = char_stats.get("cuong_the", 50)
        than_phap = char_stats.get("than_phap", 50)
        than_niem = char_stats.get("than_niem", 50)

        # 1. Quality scaling (0-20% = +0% to +20% base damage)
        quality_factor = 1.0 + (max(0, min(20, weapon.quality)) * 0.01)
        base_min = tpl.min_damage * quality_factor
        base_max = tpl.max_damage * quality_factor

        # 2. Attribute Scaling Factors
        # Physique (+0.2% melee/phys per point)
        # Agility (+0.15% attack speed, +0.1% crit per point)
        # Mind (+0.2% elemental per point)
        dmg_scale = 1.0
        if tpl.weapon_class in (WeaponClass.BLADE, WeaponClass.BLUNT_HAMMER):
            dmg_scale += (cuong_the * 0.003) + (than_phap * 0.001)
        elif tpl.weapon_class in (WeaponClass.SWORD, WeaponClass.RANGED_BOW):
            dmg_scale += (than_phap * 0.003) + (cuong_the * 0.001)
        elif tpl.weapon_class == WeaponClass.STAFF:
            dmg_scale += (than_niem * 0.0035) + (cuong_the * 0.0008)
        else: # FERAL_CLAW
            dmg_scale += (cuong_the * 0.002) + (than_phap * 0.002)

        scaled_min = base_min * dmg_scale
        scaled_max = base_max * dmg_scale

        # 3. Two-Handed Potency
        is_two_handed = (grip_style == GripStyle.TWO_HANDED) or (tpl.grip_style == GripStyle.TWO_HANDED)
        stun_potency = 1.0
        reach = tpl.weapon_range_meters

        if is_two_handed:
            scaled_min *= 1.50 # +50% More Base Damage
            scaled_max *= 1.50
            stun_potency = 1.35
            reach = max(2.0, tpl.weapon_range_meters)

        # 4. Attack Speed & Dual Wielding
        aps_scale = 1.0 + (than_phap * 0.0015)
        effective_aps = tpl.attacks_per_second * aps_scale
        bonus_block = 0.0
        is_dual_wield = False

        if not is_two_handed and offhand_weapon is not None:
            if offhand_weapon.template.grip_style == GripStyle.ONE_HANDED:
                # Dual Wield active
                is_dual_wield = True
                effective_aps *= (1.0 + self.dual_wield_rules.more_attack_speed)
                bonus_block = self.dual_wield_rules.bonus_block_chance

        # 5. Crit Chance Scaling
        crit_scale = 1.0 + (than_phap * 0.001)
        final_crit = min(0.95, tpl.base_crit_chance * crit_scale)

        # 6. Effective DPS computation
        avg_hit = (scaled_min + scaled_max) / 2.0
        crit_multiplier = 1.50
        effective_dps = avg_hit * effective_aps * (1.0 + final_crit * (crit_multiplier - 1.0))

        return WeaponScalingResult(
            min_damage=scaled_min,
            max_damage=scaled_max,
            effective_attack_speed=effective_aps,
            final_crit_chance=final_crit,
            effective_dps=effective_dps,
            weapon_reach_meters=reach,
            stun_potency_multiplier=stun_potency,
            bonus_block_chance=bonus_block,
            is_two_handed=is_two_handed,
            is_dual_wield=is_dual_wield,
        )

    def get_affinity_resonance(
        self,
        weapon: EquippedWeapon,
        char_sect: MartialSect,
        char_clan: PrimalClan
    ) -> AffinityResonanceResult:
        """Đánh giá cộng hưởng sức mạnh khi trang bị vũ khí khớp Tông Môn và Cổ Tộc."""
        tpl = weapon.template
        sect_match = (tpl.sect_affinity == char_sect)
        clan_match = (tpl.clan_affinity == char_clan)

        dmg_mult = 1.0
        bonus_crit = 0.0
        bonus_stun = 0.0
        notes = []

        if sect_match:
            dmg_mult += 0.10
            bonus_crit += 0.15
            notes.append(f"Chính Tông {char_sect.value}: +10% Sát thương, +15% Bạo Kích")
        if clan_match:
            dmg_mult += 0.08
            bonus_stun += 0.20
            notes.append(f"Huyết Mạch {char_clan.value}: +8% Sát thương, +20% Choáng váng")

        desc = " | ".join(notes) if notes else "Không có cộng hưởng môn phái/tộc hệ"

        return AffinityResonanceResult(
            has_sect_resonance=sect_match,
            has_clan_resonance=clan_match,
            total_damage_multiplier=dmg_mult,
            bonus_crit_multiplier=bonus_crit,
            bonus_stun_duration=bonus_stun,
            description=desc,
        )

    def resolve_auto_swap(
        self,
        current_active_set: int,
        weapon_set_1: WeaponSetLoadout,
        weapon_set_2: WeaponSetLoadout,
        required_category: WeaponCategory
    ) -> AutoSwapResult:
        """
        Thuật toán giải quyết Song Binh Tự Động Hoán Đổi (Dual Savage Auto-Swap in 0ms).
        Tự động chuyển vũ khí khớp với yêu cầu của chiêu thức mà không làm ngắt chuỗi combo.
        """
        if required_category == WeaponCategory.ANY:
            active_set = weapon_set_1 if current_active_set == 1 else weapon_set_2
            return AutoSwapResult(
                swapped=False,
                new_active_set=current_active_set,
                selected_weapon=active_set.mainhand,
                reason="Chiêu thức chấp nhận mọi loại vũ khí (ANY)"
            )

        def matches(loadout: WeaponSetLoadout, cat: WeaponCategory) -> Tuple[bool, Optional[EquippedWeapon]]:
            if loadout.mainhand and loadout.mainhand.template.category == cat:
                return True, loadout.mainhand
            if loadout.offhand and loadout.offhand.template.category == cat:
                return True, loadout.offhand
            return False, None

        current_loadout = weapon_set_1 if current_active_set == 1 else weapon_set_2
        has_curr, wpn_curr = matches(current_loadout, required_category)

        if has_curr:
            return AutoSwapResult(
                swapped=False,
                new_active_set=current_active_set,
                selected_weapon=wpn_curr,
                reason=f"Bộ {current_active_set} đã sẵn sàng với vũ khí {required_category.value}"
            )

        # Check alternative set
        alt_set_num = 2 if current_active_set == 1 else 1
        alt_loadout = weapon_set_2 if current_active_set == 1 else weapon_set_1
        has_alt, wpn_alt = matches(alt_loadout, required_category)

        if has_alt:
            return AutoSwapResult(
                swapped=True,
                new_active_set=alt_set_num,
                selected_weapon=wpn_alt,
                reason=f"Tự động hoán chuyển sang Bộ {alt_set_num} (Khớp {required_category.value}) trong 0ms"
            )

        return AutoSwapResult(
            swapped=False,
            new_active_set=current_active_set,
            selected_weapon=current_loadout.mainhand,
            reason=f"Cảnh báo: Không có bộ vũ khí nào thỏa mãn yêu cầu {required_category.value}"
        )

    def evaluate_loadout(self, loadout: WeaponSetLoadout, char_stats: Dict[str, int]) -> LoadoutEvaluationResult:
        """Tổng hợp toàn bộ chỉ số công thủ của một bộ vũ khí (Mainhand + Offhand)."""
        main = loadout.mainhand
        off = loadout.offhand

        if not main:
            return LoadoutEvaluationResult(
                has_shield=False,
                is_dual_wield=False,
                total_block_chance=0.0,
                bonus_armor=0.0,
                bonus_ward=0.0,
                combined_dps=0.0
            )

        main_res = self.calculate_weapon_damage(main, char_stats, main.template.grip_style, offhand_weapon=off)
        has_shield = False
        block_chance = main_res.bonus_block_chance
        bonus_armor = 0.0
        bonus_ward = 0.0

        if off and off.template.weapon_class == WeaponClass.SHIELD:
            has_shield = True
            if off.template.implicit_mod and off.template.implicit_mod.stat == WeaponImplicitStat.BLOCK_CHANCE:
                block_chance += off.template.implicit_mod.value
            bonus_armor += (char_stats.get("cuong_the", 50) * 2.5)
            if off.template.element == FiveElements.THUY:
                bonus_ward += 100.0

        return LoadoutEvaluationResult(
            has_shield=has_shield,
            is_dual_wield=main_res.is_dual_wield,
            total_block_chance=block_chance,
            bonus_armor=bonus_armor,
            bonus_ward=bonus_ward,
            combined_dps=main_res.effective_dps
        )
