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

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);
    }
};

struct DetectionRegionConfig {
    float angleSize = 360.0f;
    float radius = 99.9f;
    float height = 99.9f;
    float effectiveDistance = 9999.0f;
    float duration = 9999.0f;
    float judgmentDelay = 0.0001f;
    bool adaptation = true;
    float upperLimitThresholdSize = 99.9f;
    float movementCompensation = 99.9f;
    float jumpCompensation = 99.9f;
    float vestCompensation = 99.9f;
    float stationaryCompensation = 99.9f;
    float globalScale = 99.9f;
    float extraRadiusMultiplier = 99.9f;
    bool noBackfaceCulling = true;
    bool forceSphereCast = true;
    bool ignoreOcclusion = true;
    bool affectOnlyTarget = false;
};

static DetectionRegionConfig MaximizeConfig() {
    DetectionRegionConfig c{};
    c.radius = 1e9f;
    c.height = 1e9f;
    c.effectiveDistance = 1e9f;
    c.duration = 1e9f;
    c.angleSize = 360.0f;
    c.ignoreOcclusion = true;
    c.affectOnlyTarget = false;
    return c;
}

class DetectionRegionManager {
private:
    std::unordered_map<std::string, DetectionRegionConfig> configs;
public:
    void loadConfig(const std::string& name, const DetectionRegionConfig& cfg) {
        configs[name] = cfg;
    }
    const DetectionRegionConfig* getConfig(const std::string& name) const {
        auto it = configs.find(name);
        return (it == configs.end()) ? nullptr : &it->second;
    }
    void initDefaults() {
        loadConfig("DRV_Head", DetectionRegionConfig{});
        loadConfig("DRV_Body", DetectionRegionConfig{});
        loadConfig("DRV_Limb", DetectionRegionConfig{});
    }
};

class Entity {
public:
    Vector2 pos;
    float HP = 100.0f;
    Vector2 Pos() const { return pos; }
    void OnHit() {}
};

using DamageFunc = std::function<void(class HitCircle&, Entity&, float)>;

class HitCircle {
private:
    Vector2 center;
    float radius;
    float damage;
    const DetectionRegionConfig* cfg;
public:
    DamageFunc onHit;
    HitCircle(const Vector2& c, float r, float d, const DetectionRegionConfig* p = nullptr)
        : center(c), radius(r), damage(d), cfg(p) {}
    bool IsPointInRange(const Vector2& point) const {
        return center.Distance(point) <= radius;
    }
    bool CheckCollision(const HitCircle& other) const {
        return center.Distance(other.center) <= (radius + other.radius);
    }
    void FixCollision(HitCircle& other) {
        Vector2 dir(other.center.x - center.x, other.center.y - center.y);
        float dist = center.Distance(other.center);
        if (dist < (radius + other.radius) && dist > 0.0001f) {
            float overlap = (radius + other.radius) - dist;
            float move = overlap * 0.5f;
            Vector2 n(dir.x / dist, dir.y / dist);
            center.x -= n.x * move;
            center.y -= n.y * move;
            other.center.x += n.x * move;
            other.center.y += n.y * move;
        }
    }
    void ApplyDamage(Entity& victim) {
        if (IsPointInRange(victim.Pos()) && onHit) {
            onHit(*this, victim, damage);
        }
    }
    Vector2 GetCenter() const { return center; }
    float GetRadius() const { return radius; }
    float GetDamage() const { return damage; }
    void SetCenter(const Vector2& v) { center = v; }
    void SetRadius(float r) { radius = r; }
    const DetectionRegionConfig* GetConfig() const { return cfg; }
};

class HitCircleManager {
private:
    std::vector<HitCircle> circles;
    DetectionRegionManager drm;
public:
    HitCircleManager() { drm.initDefaults(); }
    void LoadConfig(const std::string& name, const DetectionRegionConfig& cfg) {
        drm.loadConfig(name, cfg);
    }
    const DetectionRegionConfig* GetConfig(const std::string& name) const {
        return drm.getConfig(name);
    }
    void AddCircle(const HitCircle& c) { circles.push_back(c); }
    void AddCircle(const Vector2& center, float radius, float damage,
                   const DetectionRegionConfig* cfg = nullptr,
                   DamageFunc fn = nullptr) {
        circles.emplace_back(center, radius, damage, cfg);
        if (fn) circles.back().onHit = fn;
    }
    void FixAllCollisions() {
        for (size_t i = 0; i < circles.size(); ++i)
            for (size_t j = i + 1; j < circles.size(); ++j)
                circles[i].FixCollision(circles[j]);
    }
    void CheckAndApplyDamage(std::vector<Entity>& world) {
        const float r = circles.empty() ? 0 : circles[0].GetRadius();
        const Vector2 c = circles.empty() ? Vector2() : circles[0].GetCenter();
        for (auto& e : world) {
            if (std::abs(e.Pos().x - c.x) > r) continue;
            if (std::abs(e.Pos().y - c.y) > r) continue;
            for (auto& circle : circles) circle.ApplyDamage(e);
        }
    }
    void DisplayCircles() const {
        std::cout << circles.size() << '\n';
        for (size_t i = 0; i < circles.size(); ++i) {
            const auto& c = circles[i];
            std::cout << i << ' ' << c.GetCenter().x << ' '
                      << c.GetCenter().y << ' ' << c.GetRadius()
                      << ' ' << c.GetDamage() << '\n';
        }
    }
};

int main() {
    HitCircleManager mgr;
    mgr.AddCircle(Vector2(0, 0), 1e9f, 9999.f,
                  &MaximizeConfig(),
                  [](HitCircle&, Entity& e, float dmg) {
                      e.HP -= dmg;
                      e.OnHit();
                  });

    std::vector<Entity> world(5);
    for (size_t i = 0; i < world.size(); ++i) {
        world[i].pos = Vector2(static_cast<float>(i * 2), 0);
    }

    mgr.FixAllCollisions();
    mgr.CheckAndApplyDamage(world);

    for (size_t i = 0; i < world.size(); ++i) {
        std::cout << i << ' ' << world[i].HP << '\n';
    }
    return 0;
}
