#pragma once

#include <string>
#include <vector>
#include <algorithm>
#include <cmath>

#include "foundation/math/Geometry.h"
#include "foundation/types/Color.h"

namespace ta::features::esp
{
struct EspExfil
{
    std::string name;
    int status = 0;
    ta::foundation::math::Vector3 pos3d = {};
    bool operator==(const EspExfil&) const = default;
};

struct EspTransit
{
    std::string name;
    ta::foundation::math::Vector3 pos3d = {};
    bool operator==(const EspTransit&) const = default;
};

struct EspPlayer
{
    std::string name;
    bool pmc = false;
    ta::foundation::math::Vector3 pos3d = {};
    bool operator==(const EspPlayer&) const = default;
};

enum class EspLootType : char
{
    Normal,
    Wishlist,
    QuestItem,
    Corpse,
    Container
};

struct EspLootEntry
{
    std::string name;
    ta::foundation::math::Vector3 pos3d = {};
    EspLootType type = EspLootType::Normal;
    bool operator==(const EspLootEntry&) const = default;
};

struct EspWorldSnapshot
{
    ta::foundation::math::Vector3 local_position = {};
    std::vector<EspExfil> exfils;
    std::vector<EspTransit> transits;
    std::vector<EspPlayer> players;
    std::vector<EspLootEntry> loot;

    bool operator==(const EspWorldSnapshot&) const = default;

    void clear_raid_data()
    {
        local_position = {};
        exfils.clear();
        transits.clear();
        players.clear();
        loot.clear();
    }
};

struct EspAdvancedSettings
{
    int local_position_interval_ms = 50;
    int player_scan_interval_ms = 100;
    int dynamic_loot_interval_ms = 500;
    int exfil_status_interval_ms = 500;
    int static_discovery_interval_ms = 5000;
    int wishlist_fallback_interval_ms = 3000;

    float distance_hysteresis_percent = 5.0f;

    int missing_scans_before_removal = 2;
    int metadata_resolves_per_tick = 128;
    int metadata_time_budget_us = 1500;

    bool operator==(const EspAdvancedSettings&) const = default;
};

namespace esp_advanced_limits
{
    inline constexpr int local_position_min_ms = 16;
    inline constexpr int local_position_max_ms = 200;
    inline constexpr int player_scan_min_ms = 50;
    inline constexpr int player_scan_max_ms = 500;
    inline constexpr int dynamic_loot_min_ms = 200;
    inline constexpr int dynamic_loot_max_ms = 2000;
    inline constexpr int exfil_status_min_ms = 200;
    inline constexpr int exfil_status_max_ms = 2000;
    inline constexpr int static_discovery_min_ms = 1000;
    inline constexpr int static_discovery_max_ms = 15000;
    inline constexpr int wishlist_fallback_min_ms = 1000;
    inline constexpr int wishlist_fallback_max_ms = 10000;
    inline constexpr float distance_hysteresis_min_percent = 0.0f;
    inline constexpr float distance_hysteresis_max_percent = 20.0f;
    inline constexpr int missing_scans_min = 1;
    inline constexpr int missing_scans_max = 5;
    inline constexpr int metadata_resolves_min = 16;
    inline constexpr int metadata_resolves_max = 512;
    inline constexpr int metadata_time_budget_min_us = 500;
    inline constexpr int metadata_time_budget_max_us = 5000;
}

inline void sanitize_esp_settings(EspAdvancedSettings& value)
{
    value.local_position_interval_ms = (std::clamp)(
        value.local_position_interval_ms,
        esp_advanced_limits::local_position_min_ms,
        esp_advanced_limits::local_position_max_ms);
    value.player_scan_interval_ms = (std::clamp)(
        value.player_scan_interval_ms,
        esp_advanced_limits::player_scan_min_ms,
        esp_advanced_limits::player_scan_max_ms);
    value.dynamic_loot_interval_ms = (std::clamp)(
        value.dynamic_loot_interval_ms,
        esp_advanced_limits::dynamic_loot_min_ms,
        esp_advanced_limits::dynamic_loot_max_ms);
    value.exfil_status_interval_ms = (std::clamp)(
        value.exfil_status_interval_ms,
        esp_advanced_limits::exfil_status_min_ms,
        esp_advanced_limits::exfil_status_max_ms);
    value.static_discovery_interval_ms = (std::clamp)(
        value.static_discovery_interval_ms,
        esp_advanced_limits::static_discovery_min_ms,
        esp_advanced_limits::static_discovery_max_ms);
    value.wishlist_fallback_interval_ms = (std::clamp)(
        value.wishlist_fallback_interval_ms,
        esp_advanced_limits::wishlist_fallback_min_ms,
        esp_advanced_limits::wishlist_fallback_max_ms);
    value.distance_hysteresis_percent = (std::clamp)(
        value.distance_hysteresis_percent,
        esp_advanced_limits::distance_hysteresis_min_percent,
        esp_advanced_limits::distance_hysteresis_max_percent);
    value.missing_scans_before_removal = (std::clamp)(
        value.missing_scans_before_removal,
        esp_advanced_limits::missing_scans_min,
        esp_advanced_limits::missing_scans_max);
    value.metadata_resolves_per_tick = (std::clamp)(
        value.metadata_resolves_per_tick,
        esp_advanced_limits::metadata_resolves_min,
        esp_advanced_limits::metadata_resolves_max);
    value.metadata_time_budget_us = (std::clamp)(
        value.metadata_time_budget_us,
        esp_advanced_limits::metadata_time_budget_min_us,
        esp_advanced_limits::metadata_time_budget_max_us);
}

struct EspSettingsSnapshot
{
    bool extracts_enabled = false;
    ta::foundation::RgbaColor extracts_color = {108.0f / 255.0f, 159.0f / 255.0f, 4.0f / 255.0f, 1.0f};

    bool transits_enabled = false;
    ta::foundation::RgbaColor transits_color = {176.0f / 255.0f, 100.0f / 255.0f, 53.0f / 255.0f, 1.0f};

    bool pmc_enabled = false;
    ta::foundation::RgbaColor pmc_color = {1.0f, 92.0f / 255.0f, 87.0f / 255.0f, 1.0f};

    bool scav_enabled = false;
    ta::foundation::RgbaColor scav_color = {86.0f / 255.0f, 180.0f / 255.0f, 233.0f / 255.0f, 1.0f};

    bool normal_items_enabled = false;
    ta::foundation::RgbaColor normal_item_color = {183.0f / 255.0f, 196.0f / 255.0f, 208.0f / 255.0f, 1.0f};
    float normal_item_distance = 20.f;

    float loot_min_distance = 0.f;

    bool wishlist_items_enabled = false;
    ta::foundation::RgbaColor wishlist_item_color = {216.0f / 255.0f, 107.0f / 255.0f, 1.0f, 1.0f};
    float wishlist_item_distance = 200.f;

    bool quest_items_enabled = false;
    ta::foundation::RgbaColor quest_item_color = {1.0f, 224.0f / 255.0f, 102.0f / 255.0f, 1.0f};
    float quest_item_distance = 200.f;

    bool corpses_enabled = false;
    ta::foundation::RgbaColor corpse_color = {154.0f / 255.0f, 143.0f / 255.0f, 175.0f / 255.0f, 1.0f};
    float corpse_distance = 20.f;

    bool containers_enabled = false;
    ta::foundation::RgbaColor container_color = {82.0f / 255.0f, 199.0f / 255.0f, 165.0f / 255.0f, 1.0f};
    float container_distance = 20.f;

    int font_size = 12;

    EspAdvancedSettings advanced{};

    bool operator==(const EspSettingsSnapshot&) const = default;

    bool scan_players() const
    {
        return pmc_enabled || scav_enabled;
    }

    bool scan_loot_items() const
    {
        return normal_items_enabled || wishlist_items_enabled || quest_items_enabled;
    }

    bool scan_any_loot() const
    {
        return scan_loot_items() || corpses_enabled || containers_enabled;
    }

    bool draw_any_loot() const
    {
        return normal_items_enabled || wishlist_items_enabled || quest_items_enabled ||
               corpses_enabled || containers_enabled;
    }

};

struct EspLootStyle
{
    bool enabled = false;
    ta::foundation::RgbaColor color = {1, 1, 1, 1};
    float max_distance = 0.0f;
};

inline EspLootStyle resolve_esp_loot_style(const EspSettingsSnapshot& settings, const EspLootType type)
{
    switch (type)
    {
    case EspLootType::Normal:
        return {settings.normal_items_enabled, settings.normal_item_color, settings.normal_item_distance};
    case EspLootType::Wishlist:
        return {settings.wishlist_items_enabled, settings.wishlist_item_color, settings.wishlist_item_distance};
    case EspLootType::QuestItem:
        return {settings.quest_items_enabled, settings.quest_item_color, settings.quest_item_distance};
    case EspLootType::Corpse:
        return {settings.corpses_enabled, settings.corpse_color, settings.corpse_distance};
    case EspLootType::Container:
        return {settings.containers_enabled, settings.container_color, settings.container_distance};
    default:
        return {};
    }
}
}
