#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 Thông số đạn đạo / xuất chiêu của kỹ năng (Ballistic Parameters)
 * Phục vụ tính toán thời gian bay và thời điểm va chạm đón đầu.
 */
struct BallisticParams {
    float windupSeconds = 0.120f;      // Thời gian vung đòn / niệm chú trước khi đòn đánh phát ra (giây)
    float projectileSpeed = 800.0f;    // Tốc độ bay của chiêu (units/giây); 0.0f = vô hạn (hitscan / instant AoE slam)
    float maxRange = 450.0f;           // Cự ly hiệu dụng tối đa (units)
    float targetHitboxRadius = 15.0f;  // Bán kính va chạm của quái (units)
};

/**
 * @brief Kết quả giải nghiệm ngắm bắn đón đầu (Aim Solution)
 */
struct AimSolution {
    bool valid = false;                // Nghiệm có khả thi và nằm trong cự ly hiệu dụng không
    float aimTargetX = 0.0f;           // Tọa độ X thế giới cần trỏ chuột tới
    float aimTargetY = 0.0f;           // Tọa độ Y thế giới cần trỏ chuột tới
    float leadDistance = 0.0f;         // Khoảng cách đón đầu so với vị trí hiện tại của quái (units)
    float timeToImpact = 0.0f;         // Tổng thời gian từ lúc bấm phím đến lúc trúng quái (windup + flight) (giây)
    float flightTime = 0.0f;           // Thời gian bay của đạn đạo (giây)
    float targetSpeed = 0.0f;          // Tốc độ ước tính của quái (units/giây)
    float targetVelocityX = 0.0f;      // Vận tốc Vx của quái (units/giây)
    float targetVelocityY = 0.0f;      // Vận tốc Vy của quái (units/giây)
    bool clampedToWalkable = false;    // Đã được kẹp vào địa hình hợp lệ (chống bắn xuyên tường)
};

/**
 * @brief Cấu hình bộ điều khiển ngắm đón đầu (Predictive Aim Configuration)
 */
struct PredictiveAimConfig {
    bool enabled = true;
    uint32_t historyTicks = 6;         // Số tick lấy mẫu để hồi quy vận tốc (4 - 8 ticks)
    uint32_t sampleExpiryMs = 250;     // Dữ liệu mẫu quá 250ms không thấy quái sẽ bị coi là quá hạn
    float maxPredictTime = 0.80f;      // Thời gian đón đầu tối đa (giây) để tránh ngoại suy phi lý
    float minSpeedThreshold = 10.0f;   // Dưới 10 units/s coi như quái đứng yên, không bù vận tốc
    float maxReasonableSpeed = 600.0f; // Quái POE2 di chuyển tối đa ~500-600 units/s (Rhoa charge, Boss dash)
    bool clampToTerrain = true;        // Kẹp điểm ngắm vào địa hình đi được (TerrainGrid)
};

/**
 * @brief Mẫu vị trí của thực thể theo thời gian (Zero Heap DOD)
 */
struct EntitySample {
    uint64_t timestampMs = 0;
    float posX = 0.0f;
    float posY = 0.0f;
};

static constexpr size_t kMaxSamplesPerEntity = 8;
static constexpr size_t kMaxTrackedEntities = 64;

/**
 * @brief Trạng thái theo dõi động học của một thực thể (Kinematic State)
 */
struct TrackedEntityState {
    uint32_t entityId = 0;
    uint64_t lastSeenMs = 0;
    uint8_t count = 0;
    uint8_t head = 0;
    EntitySample samples[kMaxSamplesPerEntity]{};

    float currentX = 0.0f;
    float currentY = 0.0f;
    float velocityX = 0.0f;
    float velocityY = 0.0f;
    float speed = 0.0f;

    void PushSample(uint64_t nowMs, float x, float y);
    void UpdateVelocity(uint32_t maxSamples);
};

/**
 * @brief PredictiveAimController
 * Bộ điều khiển tính toán đón đầu đạn đạo và bù trễ vung đòn (Hot Path 120Hz).
 * 100% Data-Oriented Design (DOD), Zero Dynamic Allocation.
 */
class PredictiveAimController {
public:
    explicit PredictiveAimController(const PredictiveAimConfig& config = PredictiveAimConfig{});

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

    /**
     * @brief Cập nhật vị trí các thực thể trong snapshot (Gọi tại mỗi tick 120Hz)
     * O(N) tuyến tính trên buffer tĩnh 64 thực thể.
     */
    void UpdateEntityTracking(const TelemetryPacket& packet, uint64_t nowMs);

    /**
     * @brief Tính toán nghiệm đón đầu cho mục tiêu cụ thể
     * @param targetId ID thực thể mục tiêu
     * @param playerPos Tọa độ người chơi (Shooter)
     * @param params Thông số đạn đạo của chiêu thức
     * @param terrainGrid Con trỏ địa hình (tùy chọn) để kẹp điểm ngắm
     * @return AimSolution Nghiệm đón đầu tối ưu
     */
    AimSolution SolveAim(
        uint32_t targetId,
        Vector2D playerPos,
        const BallisticParams& params,
        const navigation::TerrainGrid* terrainGrid = nullptr
    ) const;

    /**
     * @brief Tính nghiệm đón đầu trực tiếp từ tọa độ hiện tại và vector vận tốc
     */
    AimSolution SolveDirect(
        Vector2D playerPos,
        Vector2D targetPos,
        Vector2D targetVel,
        const BallisticParams& params,
        const navigation::TerrainGrid* terrainGrid = nullptr
    ) const;

    /**
     * @brief Lấy vận tốc ước tính của một thực thể
     */
    bool GetEntityVelocity(uint32_t targetId, float& outVx, float& outVy, float& outSpeed) const;

    /**
     * @brief Xóa toàn bộ dữ liệu theo dõi (khi chuyển map hoặc chết)
     */
    void Reset();

    /**
     * @brief Cấu hình kỹ năng Monk CI thông dụng trong POE2
     */
    static BallisticParams GetMonkIceStrikeParams();
    static BallisticParams GetMonkTempestBellParams();
    static BallisticParams GetMonkChargedStaffWaveParams();
    static BallisticParams GetMonkWolfLeapParams();

private:
    PredictiveAimConfig m_config;
    std::array<TrackedEntityState, kMaxTrackedEntities> m_trackedTable{};
    uint32_t m_activeTrackedCount = 0;

    int FindEntitySlot(uint32_t entityId) const;
    int AllocateEntitySlot(uint32_t entityId, uint64_t nowMs);
};

} // namespace combat
