#pragma once

#include <string>
#include <vector>
#include <cstdint>

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>

enum class SkillKind : uint8_t {
    Attack = 0,
    CombatBuff = 1,
    Persistent = 2
};

inline const char* SkillKindToString(SkillKind kind) {
    switch (kind) {
        case SkillKind::Attack: return "attack";
        case SkillKind::CombatBuff: return "combat_buff";
        case SkillKind::Persistent: return "persistent";
        default: return "unknown";
    }
}

inline SkillKind StringToSkillKind(const std::string& str) {
    if (str == "combat_buff" || str == "buff") return SkillKind::CombatBuff;
    if (str == "persistent" || str == "aura") return SkillKind::Persistent;
    return SkillKind::Attack;
}

struct SkillDefinition {
    std::string name;
    std::string key;
    uint8_t vkCode = 0;
    SkillKind kind = SkillKind::Attack;
    uint32_t priority = 1;
    uint32_t cooldownMs = 0;
    float minDistance = 0.0f;
    float maxDistance = 250.0f;
    uint8_t targetRarityMin = 0; // 0 all, 1 magic, 2 rare, 3 unique, 4 normal-only
    uint32_t closeTargets = 0;
    float closeTargetsRange = 10.0f;
    bool maintain = false;
    float minLifePct = 0.0f;
    float maxLifePct = 2.0f;
    float minManaPct = 0.0f;
    float maxManaPct = 2.0f;
    float minEsPct = 0.0f;
    float maxEsPct = 2.0f;

    uint64_t lastCastMs = 0;

    bool IsEligible(uint64_t nowMs, float dist, uint8_t rarity, float lifePct, float manaPct, float esPct, uint32_t nearbyEnemies = 0) const {
        if (lastCastMs > 0 && cooldownMs > 0 && nowMs - lastCastMs < cooldownMs) {
            return false;
        }
        if (kind == SkillKind::Attack) {
            if (dist < minDistance || dist > maxDistance) {
                return false;
            }
            if (targetRarityMin > 0 && rarity < targetRarityMin) {
                return false;
            }
            if (closeTargets > 0 && nearbyEnemies < closeTargets) {
                return false;
            }
        }
        if (lifePct < minLifePct || lifePct > maxLifePct) return false;
        if (manaPct < minManaPct || manaPct > maxManaPct) return false;
        if (esPct < minEsPct || esPct > maxEsPct) return false;
        return true;
    }
};

class SkillsTable {
public:
    SkillsTable() = default;

    bool LoadSkills(const std::string& tomlPath);
    const std::vector<SkillDefinition>& Skills() const { return m_skills; }
    std::vector<SkillDefinition>& Skills() { return m_skills; }

    SkillDefinition* SelectBestSkill(uint64_t nowMs, float dist, uint8_t rarity, float lifePct, float manaPct, float esPct, SkillKind requiredKind = SkillKind::Attack, uint32_t nearbyEnemies = 0);
    void MarkCast(const std::string& name, uint64_t nowMs);
    void MarkCastByVk(uint8_t vk, uint64_t nowMs);
    void Clear() { m_skills.clear(); }
    bool IsEmpty() const { return m_skills.empty(); }

    static uint8_t KeyStringToVk(const std::string& keyStr);

private:
    std::vector<SkillDefinition> m_skills;
};
