#include <iostream>
#include <vector>
#include <cmath>
#include <string>
#include <unordered_map>
#include <functional>
#include <algorithm>

struct Vector2 {
    float x, y;
    Vector2(float x = 0, float y = 0) : x(x), y(y) {}
    float Distance(const Vector2& other) const {
        float dx = x - other.x;
        float dy = y - other.y;
        return std::sqrt(dx * dx + dy * dy);
    }
    Vector2 Normalize() const {
        float len = Distance(Vector2(0,0));
        return (len > 0.0001f) ? Vector2(x/len, y/len) : Vector2(0,0);
    }
};

struct TrackingConfig {
    float trackingRange = 9999.0f;
    float largeRange = 9999.0f;
    float lockAngle = 360.0f;
    float lockTime = 0.01f;
    float trackingSensitivity = 1.0f;
    float trackingAcceleration = 999.0f;
    float maxDeviation = 0.1f;
    float lagCompensation = 0.0f;
    float recoilCompensation = 1.0f;
    float effectDelay = 0.0f;
    float bulletSpeed = 1000.0f;
    bool bulletTrajectoryTracking = true;
    bool largeAreaTracking = true;
    float distanceWeight = 1.0f;
    float movementWeight = 1.0f;
    float healthWeight = 1.0f;
    std::string weaponID = "Vector";
    bool burstTracking = true;
    float pelletSpreadComp = 0.1f;
};

static TrackingConfig MaximizeTrackingConfig() {
    TrackingConfig cfg{};
    cfg.trackingRange = 9999.0f;
    cfg.largeRange = 9999.0f;
    cfg.lockAngle = 360.0f;
    cfg.lockTime = 0.01f;
    cfg.trackingSensitivity = 1.0f;
    cfg.trackingAcceleration = 999.0f;
    cfg.maxDeviation = 0.1f;
    cfg.lagCompensation = 0.0f;
    cfg.recoilCompensation = 1.0f;
    cfg.effectDelay = 0.0f;
    cfg.bulletSpeed = 9999.0f;
    cfg.bulletTrajectoryTracking = true;
    cfg.largeAreaTracking = true;
    cfg.distanceWeight = 1.0f;
    cfg.movementWeight = 1.0f;
    cfg.healthWeight = 1.0f;
    cfg.weaponID = "Vector";
    cfg.burstTracking = true;
    cfg.pelletSpreadComp = 0.1f;
    return cfg;
}

struct WeaponConfig {
    std::string name = "Vector";
    float baseDamage = 9999.0f;
    float fireRate = 1100.0f;
    float range = 9999.0f;
    TrackingConfig trackingConfig;
};

class TrackingManager {
private:
    std::unordered_map<std::string, TrackingConfig> trackingConfigs;
    std::string currentWeaponID = "Vector";
public:
    TrackingManager() {
        trackingConfigs["Vector"] = MaximizeTrackingConfig();
    }
    void LoadWeaponTrackingConfig(const std::string& weaponID, const TrackingConfig& cfg) {
        trackingConfigs[weaponID] = cfg;
    }
    const TrackingConfig* GetCurrentTrackingConfig() const {
        if (currentWeaponID == "Vector") {
            auto it = trackingConfigs.find("Vector");
            return (it != trackingConfigs.end()) ? &it->second : nullptr;
        }
        return nullptr;
    }
    void SetCurrentWeapon(const std::string& weaponID) {
        currentWeaponID = weaponID;
    }
};

class Entity {
public:
    Vector2 pos;
    float HP = 100.0f;
    std::string name = "Enemy";
    Vector2 headPosOffset = Vector2(0, 1.7f);
    Vector2 bodyPosOffset = Vector2(0, 0.85f);
    Vector2 limbPosOffset = Vector2(0.3f, 0.5f);
    bool isAttackingPlayer = true;
    float movementSpeed = 10.0f;
    bool isTracked = false;
    float effectTimer = 0.0f;
    Vector2 GetHeadPos() const { return Vector2(pos.x + headPosOffset.x, pos.y + headPosOffset.y); }
    Vector2 GetBodyPos() const { return Vector2(pos.x + bodyPosOffset.x, pos.y + bodyPosOffset.y); }
    Vector2 GetLimbPos() const { return Vector2(pos.x + limbPosOffset.x, pos.y + limbPosOffset.y); }
};

class TrackingCircle {
private:
    Vector2 center;
    float radius;
    float damage;
    const TrackingConfig* trackingCfg;
    std::string hitType = "head";
    std::function<void(TrackingCircle&, Entity&, float)> onHitCallback;
    float trajectoryPredictor = 0.9f;
public:
    TrackingCircle(const Vector2& c, float r, float d, const TrackingConfig* cfg, const std::string& type = "head", std::function<void(TrackingCircle&, Entity&, float)> cb = nullptr)
        : center(c), radius(r), damage(d), trackingCfg(cfg), hitType(type), onHitCallback(cb) {}
    void TrackTarget(Entity& target, const Vector2& playerPos, float deltaTime) {
        if (!trackingCfg) return;
        Vector2 targetPos = (hitType == "head") ? target.GetHeadPos() : target.GetBodyPos();
        Vector2 predictedPos = Vector2(
            targetPos.x + target.movementSpeed * deltaTime * trajectoryPredictor,
            targetPos.y + target.movementSpeed * deltaTime * trajectoryPredictor
        );
        center = predictedPos;
        radius = trackingCfg->largeRange;
        target.isTracked = true;
        target.effectTimer = trackingCfg->effectDelay;
    }
    void ApplyTrackingDamage(Entity& victim, float deltaTime) {
        if (!trackingCfg || !onHitCallback) return;
        victim.effectTimer -= deltaTime;
        Vector2 targetPos = (hitType == "head") ? victim.GetHeadPos() : victim.GetBodyPos();
        if (center.Distance(targetPos) <= radius && victim.effectTimer <= 0.0f) {
            onHitCallback(*this, victim, damage);
            victim.HP -= damage;
            victim.effectTimer = trackingCfg->effectDelay;
        }
    }
    void UpdateTrackingParams(float deltaTime) {
        if (!trackingCfg) return;
        static float lastRecalibrate = 0.0f;
        if (deltaTime - lastRecalibrate > 0.055f) {
            radius *= trackingCfg->pelletSpreadComp;
            lastRecalibrate = deltaTime;
        }
    }
};

class WeaponManager {
private:
    std::unordered_map<std::string, WeaponConfig> weaponConfigs;
    TrackingManager trackingMgr;
public:
    WeaponManager() {
        WeaponConfig vectorCfg;
        vectorCfg.name = "Vector";
        vectorCfg.baseDamage = 9999.0f;
        vectorCfg.fireRate = 1100.0f;
        vectorCfg.range = 9999.0f;
        vectorCfg.trackingConfig = *trackingMgr.GetCurrentTrackingConfig();
        weaponConfigs["Vector"] = vectorCfg;
    }
    const WeaponConfig* GetWeaponConfig(const std::string& weaponName) const {
        if (weaponName == "Vector") {
            auto it = weaponConfigs.find("Vector");
            return (it != weaponConfigs.end()) ? &it->second : nullptr;
        }
        return nullptr;
    }
    void SwitchWeapon(const std::string& weaponName) {
        trackingMgr.SetCurrentWeapon(weaponName);
    }
};

namespace PUBGMHD_Engine {
    void Log(const std::string& msg) {
        std::cout << "[PUBGMHD_VectorTracking] " << msg << std::endl;
    }
    void RegisterUpdateCallback(std::function<void(float)> callback) {
        static float totalTime = 0.0f;
        while (true) {
            callback(1.0f/60.0f);
            totalTime += 1.0f/60.0f;
        }
    }
}

int main() {
    WeaponManager weaponMgr;
    weaponMgr.SwitchWeapon("Vector");
    const WeaponConfig* vectorCfg = weaponMgr.GetWeaponConfig("Vector");
    if (!vectorCfg) return -1;
    Entity player;
    player.pos = Vector2(0, 0);
    Entity enemy;
    enemy.pos = Vector2(100, 0);
    TrackingConfig* cfg = const_cast<TrackingConfig*>(&vectorCfg->trackingConfig);
    TrackingCircle trackingCircle(player.pos, cfg->trackingRange, vectorCfg->baseDamage, cfg, "head", [](TrackingCircle& circle, Entity& victim, float dmg) {
        PUBGMHD_Engine::Log("Vector_Tracking_Hit: " + victim.name + " HP:" + std::to_string(victim.HP));
    });
    PUBGMHD_Engine::RegisterUpdateCallback([&](float deltaTime) {
        trackingCircle.TrackTarget(enemy, player.pos, deltaTime);
        trackingCircle.ApplyTrackingDamage(enemy, deltaTime);
        trackingCircle.UpdateTrackingParams(deltaTime);
    });
    return 0;
}