"""
Server-Authoritative Combat Engine for FreeExile.
Coordinates Combat Entities, Hit Resolution, Boss Stagger Recovery,
Status Ailments, and Five Elements Interplay.
"""

from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple

from combat.combat_types import (
    AilmentApplication,
    AilmentType,
    BossPhase,
    BossStaggerState,
    CombatHitResult,
    CombatantType,
    DamageChannel,
    DamagePacket,
    DefenseSheet,
)
from combat.damage_calculator import DamageCalculator
from combat.monster_scaling import MonsterScalingEngine
from world.martial_matrix import FiveElements


@dataclass(slots=True)
class CombatEntity:
    """Runtime combat representation of a player, monster, or boss."""
    entity_id: int
    name: str
    combatant_type: CombatantType
    level: int
    element: FiveElements
    defense: DefenseSheet
    boss_stagger: Optional[BossStaggerState] = None
    boss_phase: Optional[BossPhase] = None
    last_evasion_timestamp_ms: int = 0
    evasion_iframe_duration_ms: int = 250
    active_ailments: List[AilmentApplication] = field(default_factory=list)
    last_hit_received_timestamp_ms: int = 0


class CombatEngine:
    """Central authority executing combat ticks, attacks, and state updates."""

    # Ngũ Hành Tương Khắc (Kim khắc Mộc, Mộc khắc Thổ, Thổ khắc Thủy, Thủy khắc Hỏa, Hỏa khắc Kim)
    ELEMENT_OVERCOMING = {
        FiveElements.KIM: FiveElements.MOC,
        FiveElements.MOC: FiveElements.THO,
        FiveElements.THO: FiveElements.THUY,
        FiveElements.THUY: FiveElements.HOA,
        FiveElements.HOA: FiveElements.KIM,
    }

    def __init__(self) -> None:
        self.entities: Dict[int, CombatEntity] = {}
        self.calculator = DamageCalculator()
        self.scaling = MonsterScalingEngine()

    def register_entity(self, entity: CombatEntity) -> None:
        self.entities[entity.entity_id] = entity

    def get_entity(self, entity_id: int) -> Optional[CombatEntity]:
        return self.entities.get(entity_id)

    def trigger_phantom_evasion(self, entity_id: int, current_timestamp_ms: int) -> bool:
        """Triggers Huyễn Ảnh Bộ (0.25s i-frame invulnerability window)."""
        entity = self.entities.get(entity_id)
        if not entity:
            return False
        entity.last_evasion_timestamp_ms = current_timestamp_ms
        return True

    def process_attack(
        self,
        attacker_id: int,
        defender_id: int,
        packet: DamagePacket,
        current_timestamp_ms: int,
    ) -> Optional[CombatHitResult]:
        """Processes an outgoing attack against a defender entity."""
        attacker = self.entities.get(attacker_id)
        defender = self.entities.get(defender_id)
        if not attacker or not defender:
            return None

        # 1. Check i-frame window
        elapsed = current_timestamp_ms - defender.last_evasion_timestamp_ms
        defender.defense.is_in_iframe = 0 <= elapsed <= defender.evasion_iframe_duration_ms

        # 2. Check Ngũ Hành Tương Khắc elemental bonus (+25% more elemental damage)
        if self.ELEMENT_OVERCOMING.get(attacker.element) == defender.element:
            packet.more_damage_multipliers.append(1.25)

        # 3. Execute hit via DamageCalculator
        result, next_entropy = self.calculator.execute_hit(
            packet=packet,
            defense=defender.defense,
            entropy_pool=defender.defense.entropy_pool,
            boss_stagger=defender.boss_stagger,
        )
        defender.defense.entropy_pool = next_entropy

        if result.is_hit:
            defender.last_hit_received_timestamp_ms = current_timestamp_ms

            # 4. Check Boss Phase Escalation if defender is a Boss
            if defender.combatant_type == CombatantType.BOSS:
                new_phase = self.scaling.evaluate_boss_phase(
                    current_hp=defender.defense.current_life,
                    max_hp=defender.defense.max_life,
                )
                if new_phase != defender.boss_phase:
                    defender.boss_phase = new_phase
                    result.boss_phase_transition = new_phase

        return result

    def update_tick(self, delta_sec: float, current_timestamp_ms: int) -> None:
        """Periodic server loop update (called at 30Hz or 60Hz)."""
        for entity in self.entities.values():
            # A. Boss Stagger recovery & decay
            if entity.boss_stagger:
                if entity.boss_stagger.is_staggered:
                    entity.boss_stagger.stagger_duration_remaining_sec -= delta_sec
                    if entity.boss_stagger.stagger_duration_remaining_sec <= 0.0:
                        entity.boss_stagger.is_staggered = False
                        entity.boss_stagger.stagger_duration_remaining_sec = 0.0
                        entity.boss_stagger.stagger_cooldown_remaining_sec = 8.0  # 8s immunity cooldown
                else:
                    if entity.boss_stagger.stagger_cooldown_remaining_sec > 0.0:
                        entity.boss_stagger.stagger_cooldown_remaining_sec -= delta_sec
                    # If out of combat for 5s, decay stagger poise
                    time_since_hit = (current_timestamp_ms - entity.last_hit_received_timestamp_ms) / 1000.0
                    if time_since_hit >= 5.0 and entity.boss_stagger.current_stagger > 0.0:
                        decay = entity.boss_stagger.max_stagger_poise * 0.10 * delta_sec
                        entity.boss_stagger.current_stagger = max(0.0, entity.boss_stagger.current_stagger - decay)

            # B. Ward / Energy Shield Recharge (after 4s without taking damage)
            time_since_hit = (current_timestamp_ms - entity.last_hit_received_timestamp_ms) / 1000.0
            if time_since_hit >= 4.0 and entity.defense.current_ward < entity.defense.max_ward:
                recharge_rate = entity.defense.max_ward * 0.20 * delta_sec  # 20% ward per second
                entity.defense.current_ward = min(entity.defense.max_ward, entity.defense.current_ward + recharge_rate)
