"""
Trận Đồ Võ Công (Martial Matrix Engine) & Cổ Võ Hắc Ám Skill System for FreeExile.
Manages:
- Chân Võ Đan (Active Martial Core Elixirs / Skill Gems) with distinct Sects & Elements.
- Thần Biến Phù (Transmutation Sigils / Support Gems) with deep trade-off mechanics (PoE2 spirit).
- Ma Trận Chiêu Thức (Martial Skill Matrix - 6 active slots, up to 5 linked sigils per slot).
- Phối hợp với Hệ Thống Nhân Vật: Căn Cốt (Cương Thể, Thân Pháp, Thần Niệm), Ngũ Hành, Song Binh Tự Động Hoán Đổi.
"""

from __future__ import annotations
from typing import Any, Dict, List, Optional, Tuple

from server.world.martial_types import (
    FiveElements,
    MartialSect,
    SkillTag,
    WeaponCategory,
    SigilAugmentType,
    WeaponItem,
    CharacterLoadout,
    DiBienTaAn,
    ChanVoDan,
    CalculatedSkillDamage,
)
from server.world.martial_catalog import (
    create_standard_active_skills,
    create_standard_augment_sigils,
)

__all__ = [
    "MartialMatrix",
    "ChanVoDan",
    "DiBienTaAn",
    "FiveElements",
    "MartialSect",
    "SkillTag",
    "WeaponCategory",
    "WeaponItem",
    "CharacterLoadout",
    "SigilAugmentType",
    "CalculatedSkillDamage",
    "create_standard_active_skills",
    "create_standard_augment_sigils",
]


class MartialMatrix:
    """
    Ma Trận Chiêu Thức: Quản lý 6 ô Chân Võ Đan và tối đa 5 Thần Biến Phù liên kết mỗi ô.
    Tự động thẩm định tính tương thích Tag, hoán đổi Song Binh và tính toán Trade-off.
    """
    def __init__(self, max_active_slots: int = 6):
        self.max_active_slots = max_active_slots
        self.slots: Dict[int, Optional[ChanVoDan]] = {i: None for i in range(max_active_slots)}

    def socket_active_skill(self, slot_index: int, skill: ChanVoDan) -> bool:
        if slot_index < 0 or slot_index >= self.max_active_slots:
            return False
        self.slots[slot_index] = skill
        return True

    def remove_active_skill(self, slot_index: int) -> Optional[ChanVoDan]:
        return self.slots.pop(slot_index, None)

    def get_active_skill(self, slot_index: int) -> Optional[ChanVoDan]:
        return self.slots.get(slot_index)

    def link_sigil_to_skill(self, slot_index: int, sigil: DiBienTaAn) -> Tuple[bool, str]:
        """
        Liên kết Thần Biến Phù vào Chân Võ Đan tại ô slot_index.
        Kiểm tra nghiêm ngặt tính tương thích nhãn (Tag Compatibility) và giới hạn 5 phù.
        """
        skill = self.slots.get(slot_index)
        if not skill:
            return False, f"Ô số {slot_index} chưa cắm Chân Võ Đan"

        if len(skill.linked_sigils) >= skill.max_linked_sigils:
            return False, f"Đã đạt tối đa {skill.max_linked_sigils} Thần Biến Phù liên kết"

        # Kiểm tra Tag Compatibility: Các tag bắt buộc của Sigil phải nằm trong Tag của Skill
        if sigil.required_tags and not sigil.required_tags.issubset(skill.tags):
            missing_tags = [t.value for t in (sigil.required_tags - skill.tags)]
            return False, f"Thần Biến Phù '{sigil.sigil_name}' không tương thích: thiếu tag {missing_tags}"

        # Kiểm tra Tag Xung Đột (Excluded Tags): Chiêu không được chứa bất kỳ tag nào bị cấm
        if hasattr(sigil, "excluded_tags") and sigil.excluded_tags and (sigil.excluded_tags & skill.tags):
            conflict_tags = [t.value for t in (sigil.excluded_tags & skill.tags)]
            return False, f"Thần Biến Phù '{sigil.sigil_name}' xung đột với tag của chiêu thức: {conflict_tags}"

        skill.linked_sigils.append(sigil)
        return True, "Liên kết Thần Biến Phù thành công"

    def resolve_weapon_swap(
        self,
        character: CharacterLoadout,
        skill: ChanVoDan
    ) -> Tuple[bool, int, str]:
        """
        Cơ chế Song Binh Tự Động Hoán Đổi (PoE2 Spirit Dual Weapon Auto-Swap).
        Nếu bộ vũ khí đang cầm không khớp với yêu cầu của chiêu thức,
        hệ thống tự động kiểm tra bộ vũ khí phụ và hoán đổi trong 0ms.
        """
        req = skill.weapon_requirement
        if req == WeaponCategory.ANY:
            return True, character.active_weapon_set, "Chiêu thức không yêu cầu vũ khí đặc định"

        cur_weapon = character.weapon_set_1 if character.active_weapon_set == 1 else character.weapon_set_2
        if cur_weapon and cur_weapon.category == req:
            return True, character.active_weapon_set, "Vũ khí hiện tại tương thích"

        # Kiểm tra bộ vũ khí còn lại để tự động hoán đổi
        alt_set = 2 if character.active_weapon_set == 1 else 1
        alt_weapon = character.weapon_set_2 if character.active_weapon_set == 1 else character.weapon_set_1

        if alt_weapon and alt_weapon.category == req:
            character.active_weapon_set = alt_set
            return True, alt_set, f"Tự động hoán đổi sang Bộ Vũ Khí {alt_set} ({alt_weapon.name}) để xuất chiêu"

        return False, character.active_weapon_set, f"Cả 2 bộ vũ khí đều không thỏa mãn yêu cầu '{req.value}' của chiêu thức"

    def compute_modified_skill(
        self,
        slot_index: int,
        character: Optional[CharacterLoadout] = None
    ) -> Optional[Dict[str, Any]]:
        """
        Tính toán toàn bộ thuộc tính thực thi của chiêu thức:
        - Tác động lũy tích của các Thần Biến Phù (Trade-off Matrix).
        - Tỉ lệ khuếch đại từ Căn Cốt nhân vật (Cương Thể, Thân Pháp, Thần Niệm).
        - Phạt Chân Khí / Khí Huyết, độ giật phản chấn, cấm đoán chiến thuật.
        """
        skill = self.slots.get(slot_index)
        if not skill:
            return None

        # 1. Base Stats
        base_damage = skill.base_damage
        effective_damage = base_damage
        total_projectiles = skill.base_projectile_count
        effective_aoe = skill.base_aoe_radius
        total_chains = 0
        effective_energy = float(skill.energy_cost)
        effective_cooldown = float(skill.cooldown_ms)
        effective_cast_speed = 1.0
        effective_crit_chance = 0.05
        effective_crit_mult = 1.50
        effective_animation_lock = skill.animation_lock_ms
        effective_vulnerability = skill.vulnerability_taken_multiplier
        total_recoil_pct = 0.0
        converts_to_life = False
        ward_disabled = False
        elemental_disabled = False
        physical_disabled = False
        piercing_disabled = False
        freeze_chance = 0.0
        ignite_poison_disabled = False
        dash_distance = 0.0

        # 2. Character Attributes Scaling
        if character:
            if SkillTag.MELEE in skill.tags or SkillTag.SLAM in skill.tags:
                physique_mult = 1.0 + (character.cuong_the * 0.002)
                effective_damage *= physique_mult

            agility_speed = 1.0 + (character.than_phap * 0.0015)
            effective_cast_speed *= agility_speed
            effective_crit_chance += (character.than_phap * 0.001)

            if SkillTag.SPELL in skill.tags or skill.element != FiveElements.THO:
                spirit_mult = 1.0 + (character.than_niem * 0.002)
                effective_damage *= spirit_mult

        # 3. Apply Linked Sigils (Thần Biến Phù Trade-offs)
        for sigil in skill.linked_sigils:
            if sigil.required_tags and not sigil.required_tags.issubset(skill.tags):
                continue

            effective_damage *= sigil.damage_multiplier
            total_projectiles += sigil.projectile_bonus
            effective_aoe = (effective_aoe + sigil.aoe_radius_bonus) * sigil.aoe_radius_multiplier
            total_chains += sigil.chain_count_bonus
            effective_energy *= sigil.energy_cost_multiplier
            effective_cooldown *= sigil.cooldown_multiplier
            effective_cast_speed *= sigil.cast_speed_multiplier
            effective_crit_chance *= sigil.crit_chance_multiplier
            effective_crit_mult += sigil.crit_multiplier_bonus
            total_recoil_pct += sigil.recoil_damage_percent

            if sigil.converts_cost_to_life:
                converts_to_life = True
            if sigil.disables_ward:
                ward_disabled = True
            if sigil.disables_elemental_damage:
                elemental_disabled = True
            if sigil.disables_physical_damage:
                physical_disabled = True
            if sigil.disables_piercing:
                piercing_disabled = True
            if sigil.forces_freeze_chance > freeze_chance:
                freeze_chance = sigil.forces_freeze_chance
            if sigil.disables_ignite_and_poison:
                ignite_poison_disabled = True
            if sigil.dash_evasion_distance > 0.0:
                dash_distance += sigil.dash_evasion_distance

        # 4. Enforce Inherent Skill Trade-Off Constraints
        if skill.cannot_crit:
            effective_crit_chance = 0.0

        if not skill.direct_hit_enabled:
            effective_damage = 0.0

        final_resource_cost = int(round(effective_energy))
        cost_type = "KHÍ_HUYẾT" if converts_to_life else "CHÂN_KHÍ"

        return {
            "skill_id": skill.skill_id,
            "skill_name": skill.skill_name,
            "element": skill.element.value,
            "sect": skill.sect.value,
            "tags": [t.value for t in skill.tags],
            "effective_damage": round(effective_damage, 2),
            "projectile_count": total_projectiles,
            "aoe_radius": round(effective_aoe, 2),
            "chain_count": total_chains,
            "cost_value": final_resource_cost,
            "cost_type": cost_type,
            "cooldown_ms": int(round(effective_cooldown)),
            "cast_time_ms": int(round(skill.cast_time_ms / effective_cast_speed)),
            "animation_lock_ms": effective_animation_lock,
            "vulnerability_multiplier": effective_vulnerability,
            "crit_chance": round(min(1.0, max(0.0, effective_crit_chance)), 4),
            "crit_multiplier": round(effective_crit_mult, 2),
            "recoil_damage_percent": round(total_recoil_pct, 4),
            "dot_multiplier": skill.dot_multiplier,
            "dot_duration_sec": skill.dot_duration_sec,
            "speed_penalty_percent": skill.speed_penalty_percent,
            "self_damage_max_hp_percent": skill.self_damage_max_hp_percent,
            "minimum_range_meters": skill.minimum_range_meters,
            "immobilized_during_effect": skill.immobilized_during_effect,
            "ward_disabled": ward_disabled,
            "elemental_disabled": elemental_disabled,
            "physical_disabled": physical_disabled,
            "piercing_disabled": piercing_disabled,
            "freeze_chance": freeze_chance,
            "ignite_poison_disabled": ignite_poison_disabled,
            "dash_distance": dash_distance,
            "upside_summary": skill.upside_desc,
            "downside_summary": skill.downside_desc,
        }
