#pragma once

#include <cstdint>
#include <cmath>
#include <algorithm>

namespace FreeExile {

enum class FiveElements : uint8_t {
    KIM = 1,   // Metal (Phys/Kim)
    MOC = 2,   // Wood (Poison/Mộc)
    THUY = 3,  // Water (Cold/Thủy)
    HOA = 4,   // Fire (Fire/Hỏa)
    THO = 5    // Earth (Stun/Thổ)
};

enum class CombatantRank : uint8_t {
    PLAYER = 0,
    COMMON = 1,
    MAGIC = 2,
    RARE = 3,
    BOSS = 4
};

struct DamageResult {
    int32_t attacker_id;
    int32_t defender_id;
    float final_damage;
    float absorbed_by_ward;
    float damage_to_life;
    bool is_critical;
    bool is_evaded;          // Huyễn Ảnh Bộ 0.25s i-frame or Evasion
    bool boss_staggered;     // PoE2 Boss Stagger triggered
};

class NativeCombatEngine {
public:
    static inline bool is_overcoming(FiveElements attacker_elem, FiveElements defender_elem) {
        // 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
        switch (attacker_elem) {
            case FiveElements::KIM: return defender_elem == FiveElements::MOC;
            case FiveElements::MOC: return defender_elem == FiveElements::THO;
            case FiveElements::THO: return defender_elem == FiveElements::THUY;
            case FiveElements::THUY: return defender_elem == FiveElements::HOA;
            case FiveElements::HOA: return defender_elem == FiveElements::KIM;
            default: return false;
        }
    }

    /// Path of Exile Non-Linear Armour Damage Reduction formula:
    /// DR = Armour / (Armour + 5.0 * Damage), capped at 90%.
    static inline float calculate_armour_mitigation(float armour, float incoming_phys) {
        if (incoming_phys <= 0.0f || armour <= 0.0f) return 0.0f;
        float dr = armour / (armour + 5.0f * incoming_phys);
        return std::clamp(dr, 0.0f, 0.90f);
    }

    /// Resistance mitigation with max cap and penetration:
    static inline float calculate_resistance_mitigation(float res, float max_cap = 0.75f, float penetration = 0.0f) {
        float effective_res = std::min(res, max_cap) - penetration;
        effective_res = std::max(-2.00f, effective_res);
        return 1.0f - effective_res;
    }

    /// High-performance hit calculation supporting Armour, Resistances, Ward, and Boss Stagger
    static DamageResult calculate_damage_advanced(
        int32_t attacker_id,
        int32_t defender_id,
        float raw_phys_damage,
        float raw_elemental_damage,
        FiveElements atk_element,
        FiveElements def_element,
        float defender_armour,
        float defender_resistance,
        float& defender_current_ward,
        float& defender_current_life,
        bool defender_in_iframe,
        float elemental_penetration = 0.0f,
        float crit_chance = 0.15f,
        float crit_mult = 1.50f,
        bool is_boss = false,
        float* boss_current_stagger = nullptr,
        float boss_max_stagger = 0.0f,
        bool* boss_is_staggered = nullptr,
        float stagger_impact = 0.0f
    ) {
        if (defender_in_iframe) {
            return { attacker_id, defender_id, 0.0f, 0.0f, 0.0f, false, true, false };
        }

        float multiplier = 1.0f;
        if (is_overcoming(atk_element, def_element)) {
            multiplier *= 1.25f; // 25% elemental bonus
        }

        bool is_crit = (crit_chance >= 1.0f);
        if (is_crit) {
            multiplier *= crit_mult;
        }

        // 1. Physical Armour Mitigation
        float phys_dmg = raw_phys_damage * multiplier;
        float phys_dr = calculate_armour_mitigation(defender_armour, phys_dmg);
        float mitigated_phys = phys_dmg * (1.0f - phys_dr);

        // 2. Elemental Resistance Mitigation
        float ele_dmg = raw_elemental_damage * multiplier;
        float ele_mult = calculate_resistance_mitigation(defender_resistance, 0.75f, elemental_penetration);
        float mitigated_ele = ele_dmg * ele_mult;

        float total_dmg = mitigated_phys + mitigated_ele;

        // Boss Stagger Vulnerability (+30% damage taken if staggered)
        if (is_boss && boss_is_staggered && *boss_is_staggered) {
            total_dmg *= 1.30f;
        }

        // 3. Ward Pool Depletion
        float absorbed_ward = 0.0f;
        float damage_to_life = total_dmg;

        if (defender_current_ward > 0.0f) {
            if (defender_current_ward >= total_dmg) {
                absorbed_ward = total_dmg;
                defender_current_ward -= total_dmg;
                damage_to_life = 0.0f;
            } else {
                absorbed_ward = defender_current_ward;
                damage_to_life = total_dmg - defender_current_ward;
                defender_current_ward = 0.0f;
            }
        }
        defender_current_life = std::max(0.0f, defender_current_life - damage_to_life);

        // 4. Boss Stagger Accumulation
        bool stagger_triggered = false;
        if (is_boss && boss_current_stagger && boss_is_staggered && !(*boss_is_staggered)) {
            *boss_current_stagger += stagger_impact;
            if (*boss_current_stagger >= boss_max_stagger) {
                *boss_is_staggered = true;
                stagger_triggered = true;
            }
        }

        return {
            attacker_id,
            defender_id,
            total_dmg,
            absorbed_ward,
            damage_to_life,
            is_crit,
            false,
            stagger_triggered
        };
    }
};

} // namespace FreeExile
