#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif

#include <cstdint>
#include <cstddef>
#include <array>
#include <cmath>
#include <algorithm>
#include "common/protocol.hpp"
#include "common/fixed_keys.hpp"

namespace navigation { class TerrainGrid; }

namespace combat {

/**
 * @brief Hình dạng vùng sát thương telegraph của quái vật
 */
enum class TelegraphShape : uint8_t {
    Circle = 0,      // Dập sàn bán kính quanh quái / vị trí mục tiêu (Radial Slam / Nova)
    FrontalCone = 1, // Hình nón quét phía trước (Cone / Cleave / Breath)
    Rectangle = 2    // Đòn quét thẳng / tia năng lượng hình chữ nhật (Line / Beam / Shockwave)
};

/**
 * @brief Hành động né đòn được chỉ định
 */
enum class EvasionActionKind : uint8_t {
    None = 0,        // Nhân vật đang an toàn, không cần né
    StutterStep = 1, // Lách bước di chuyển (Stutter-step) vì còn nhiều thời gian
    IframeRoll = 2   // Lăn né bất tử khẩn cấp (Spacebar Dodge Roll) vì đòn sắp chạm
};

/**
 * @brief Thông tin chi tiết một mối đe dọa Telegraph đang tích tụ
 */
struct TelegraphThreat {
    uint32_t sourceEntityId = 0;
    TelegraphShape shape = TelegraphShape::Circle;
    float originX = 0.0f;
    float originY = 0.0f;
    float radius = 160.0f;         // Bán kính hình tròn, cự ly hình nón, hoặc chiều dài chữ nhật
    float widthOrHalfAngle = 60.0f;// Bán kính góc (rad) cho nón (~pi/3), hoặc bề rộng (units) cho chữ nhật
    float directionRad = 0.0f;     // Hướng tung đòn (radians)
    float timeRemainingMs = 300.0f;// Thời gian còn lại trước khi dập đòn (ms)
    float damageEstimate = 5000.0f;// Sát thương ước tính
    bool isLethalForCI = true;     // Đòn đánh có nguy cơ sốc chết Monk CI hay không
};

/**
 * @brief Quyết định né đòn từ TelegraphEvasionArbiter
 */
struct EvasionDecision {
    EvasionActionKind action = EvasionActionKind::None;
    uint32_t threatEntityId = 0;
    float evasionDirX = 0.0f;      // Vector hướng né chuẩn hóa X
    float evasionDirY = 0.0f;      // Vector hướng né chuẩn hóa Y
    float escapeDistance = 0.0f;   // Khoảng cách ngắn nhất cần thoát ra khỏi vùng nguy hiểm (units)
    float timeRemainingMs = 0.0f;  // Thời gian còn lại của telegraph nguy hiểm nhất
    const char* reason = "Safe";
};

/**
 * @brief Cấu hình bộ điều phối né đòn chủ động
 */
struct TelegraphArbiterConfig {
    bool enabled = true;
    float defaultSlamRadius = 160.0f;
    float defaultConeRadius = 220.0f;
    float defaultConeAngleRad = 1.0472f;  // 60 độ (pi / 3)
    float defaultRectLength = 260.0f;
    float defaultRectWidth = 70.0f;
    float rollUrgencyWindowMs = 380.0f;   // Dưới 380ms không kịp đi bộ -> Bắt buộc dùng Spacebar Roll
    uint32_t rollCooldownMs = 650;        // Cooldown giữa các lần lăn né
    float safetyMargin = 12.0f;           // Biên độ đệm an toàn ngoài rìa vùng nguy hiểm
    bool checkTerrain = true;             // Kẹp hướng né vào địa hình đi được
};

/**
 * @brief TelegraphEvasionArbiter
 * Bộ điều phối phân tích hình học nguy hiểm & né đòn chủ động trước khi Boss/Rare dập sàn.
 * 100% Data-Oriented Design (DOD), Zero Dynamic Allocation trên Hot Path 120Hz.
 */
class TelegraphEvasionArbiter {
public:
    explicit TelegraphEvasionArbiter(const TelegraphArbiterConfig& config = TelegraphArbiterConfig{});

    void SetConfig(const TelegraphArbiterConfig& config) { m_config = config; }
    const TelegraphArbiterConfig& Config() const { return m_config; }

    /**
     * @brief Đánh giá toàn bộ thực thể trong snapshot và đưa ra quyết định né đòn
     * @param packet Gói dữ liệu telemetry 120Hz
     * @param nowMs Timestamp thời gian thực (Unix ms)
     * @param grid Con trỏ địa hình TerrainGrid (tùy chọn) để tránh lăn vào tường
     * @return EvasionDecision Quyết định né đòn tối ưu
     */
    EvasionDecision EvaluateThreats(
        const TelemetryPacket& packet,
        uint64_t nowMs,
        const navigation::TerrainGrid* grid = nullptr
    );

    /**
     * @brief Đánh giá trực tiếp một mối đe dọa hình học cụ thể
     */
    bool EvaluateSingleThreat(
        Vector2D playerPos,
        const TelegraphThreat& threat,
        float& outEscapeDirX,
        float& outEscapeDirY,
        float& outEscapeDist
    ) const;

    /**
     * @brief Kiểm tra xem một điểm (X, Y) có nằm trong vùng nguy hiểm không
     */
    static bool IsPointInDangerZone(
        Vector2D pt,
        const TelegraphThreat& threat
    );

    /**
     * @brief Ghi nhận một lần lăn né vừa được thực thi (cập nhật cooldown)
     */
    void RecordDodgeExecuted(uint64_t nowMs);

    /**
     * @brief Trạng thái cooldown lăn né
     */
    bool IsRollOnCooldown(uint64_t nowMs) const {
        return (nowMs < m_lastRollMs + m_config.rollCooldownMs);
    }

private:
    static constexpr size_t kMaxThreats = 16;
    TelegraphArbiterConfig m_config;
    uint64_t m_lastRollMs = 0;
    uint32_t m_totalRolls = 0;
    uint32_t m_totalStutterSteps = 0;

    // Helper kiểm tra hình học
    static bool CheckCircleThreat(Vector2D player, const TelegraphThreat& t, float& outDirX, float& outDirY, float& outDist, float margin);
    static bool CheckConeThreat(Vector2D player, const TelegraphThreat& t, float& outDirX, float& outDirY, float& outDist, float margin);
    static bool CheckRectThreat(Vector2D player, const TelegraphThreat& t, float& outDirX, float& outDirY, float& outDist, float margin);
    static float WrapAngle(float angleRad);
};

} // namespace combat
