"""
Unit tests for Server-Authoritative Combat Engine & Five Elements System in FreeExile.
Verifies Five Elements mitigation formulas, critical strike calculation, and Huyễn Ảnh Bộ (Phantom Evasion) i-frame invulnerability.
"""

import unittest
import time
import sys
import os

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../server")))

from world.combat_engine import CombatEngine, CombatActor
from world.martial_matrix import FiveElements


class TestCombatEngine(unittest.TestCase):
    def setUp(self):
        self.engine = CombatEngine()
        self.attacker = CombatActor(
            actor_id=1,
            name="Kiếm Khách Hỏa Long",
            element=FiveElements.HOA,
            base_attack=100.0,
            crit_chance=0.20,
            crit_multiplier=1.5
        )
        self.defender = CombatActor(
            actor_id=2,
            name="Kim Cang Đao Khách",
            element=FiveElements.KIM,
            current_hp=500.0,
            max_hp=500.0,
            resistances={
                FiveElements.KIM: 0.10,
                FiveElements.MOC: 0.10,
                FiveElements.THUY: 0.40,
                FiveElements.HOA: 0.0,   # Hỏa khắc Kim -> low fire resistance
                FiveElements.THO: 0.20
            }
        )
        self.engine.register_actor(self.attacker)
        self.engine.register_actor(self.defender)

    def test_five_elements_damage_mitigation(self):
        """Attacker (Hỏa) attacks Defender (Kim) -> Hỏa khắc Kim deals amplified elemental damage."""
        dmg_event = self.engine.calculate_damage(
            attacker_id=1,
            defender_id=2,
            raw_damage=100.0,
            damage_element=FiveElements.HOA,
            current_timestamp_ms=int(time.time() * 1000)
        )
        self.assertFalse(dmg_event.is_evaded)
        # Hỏa khắc Kim grants an elemental advantage bonus (+25%), zero resistance -> 125 mitigated damage minimum
        self.assertGreaterEqual(dmg_event.final_damage, 120.0)
        self.assertEqual(dmg_event.element, FiveElements.HOA)

    def test_huyen_anh_bo_iframe_invulnerability(self):
        """Defender activates Huyễn Ảnh Bộ -> during 0.25s i-frame window, damage is 100% evaded."""
        now_ms = int(time.time() * 1000)
        
        # Trigger Huyễn Ảnh Bộ (Phantom Evasion) at now_ms
        self.engine.trigger_phantom_evasion(actor_id=2, timestamp_ms=now_ms)

        # Incoming attack 100ms later (within 250ms i-frame window)
        attack_time_ms = now_ms + 100
        dmg_event = self.engine.calculate_damage(
            attacker_id=1,
            defender_id=2,
            raw_damage=100.0,
            damage_element=FiveElements.HOA,
            current_timestamp_ms=attack_time_ms
        )
        self.assertTrue(dmg_event.is_evaded)
        self.assertEqual(dmg_event.final_damage, 0.0)
        # HP remains unchanged
        self.assertEqual(self.defender.current_hp, 500.0)

    def test_damage_applied_after_iframe_expires(self):
        """After 0.25s i-frame window expires (e.g. 300ms later), incoming attack deals normal damage."""
        now_ms = int(time.time() * 1000)
        self.engine.trigger_phantom_evasion(actor_id=2, timestamp_ms=now_ms)

        # Incoming attack 300ms later (after 250ms i-frame has passed)
        attack_time_ms = now_ms + 300
        dmg_event = self.engine.calculate_damage(
            attacker_id=1,
            defender_id=2,
            raw_damage=100.0,
            damage_element=FiveElements.HOA,
            current_timestamp_ms=attack_time_ms
        )
        self.assertFalse(dmg_event.is_evaded)
        self.assertGreater(dmg_event.final_damage, 0.0)


if __name__ == "__main__":
    unittest.main()
