#pragma once
#include "math.h"
#include "../memory/offsets.h"
#include "../memory/memory_reader.h"
#include <string>
#include <cstring>
#include <vector>
#include <map>

extern uintptr_t g_ApexBase;
extern DWORD g_ApexPid;
extern DriverInterfaceV3* g_Driver;
extern float g_ClosestEnemyDistance;
extern int g_AdaptiveSleepTime;

extern bool g_IsInFiringRange;




struct Entity {
    
    int index;
    uintptr_t address;
    uint64_t valid;
    
    
    Vector3 position;
    Vector3 velocity;
    
    
    int health;
    int maxHealth;
    int shield;
    int maxShield;
    int armorType;
    int team;
    int bleedoutState;
    
    
    float lastVisibleTime;
    bool isVisible;
    bool isKnocked;
    bool isDummy;
    bool isPlayer;
    
    
    float distance;
    std::vector<Vector3> cachedBones;
    bool hasBones;
    
    Entity() : index(-1), address(0), valid(0), position(), velocity(),
               health(0), maxHealth(0), shield(0), maxShield(0), armorType(0),
               team(0), bleedoutState(0), lastVisibleTime(0.0f), isVisible(false), isKnocked(false),
               isDummy(false), isPlayer(false), distance(0.0f), hasBones(false) {}
    
    
    bool IsValid() const {
        return address != 0 &&
               address != 0xCCCCCCCCCCCCCCCC &&
               address != 0xCDCDCDCDCDCDCDCD &&
               address < 0x7FFFFFFFFFFF &&
               address > 0x1000;
    }
    
    
    bool IsDummy() const {
        return isDummy;
    }
    
    
    void UpdateFromBuffer(const uint8_t* buffer, size_t bufferSize) {
        valid = 0;
        if (!buffer || bufferSize < 0x500) return;
        
        team = *(int*)(buffer + OFF_TEAM_NUMBER);
        if (team < 0 || team > 255) return; // 快速过滤无效团队

        health = *(int*)(buffer + OFF_HEALTH);
        if (health < 0 || health > 5000) return; // 快速过滤异常血量

        position = *(Vector3*)(buffer + OFF_LOCAL_ORIGIN);
        if (position.x == 0 && position.y == 0) return;
        
        maxHealth = *(int*)(buffer + OFF_MAXHEALTH);
        shield = *(int*)(buffer + OFF_SHIELD);
        maxShield = *(int*)(buffer + OFF_MAXSHIELD);
        
        // 尝试通过团队识别 Dummy
        if (team > 60 || team == 0) {
            isDummy = true;
        }

        valid = 1;
    }

    void UpdateExtendedDataBatch(uintptr_t entityAddr) {
        if (!entityAddr || !g_Driver) return;

        // 优化：合并读取更多数据 (从 Bleedout 到 ArmorType)
        // OFF_BLEEDOUT_STATE = 0x28a0
        // OFF_ARMORTYPE = 0x48f4
        uint8_t extBuffer[0x2100];
        if (g_Driver->ReadMemory(g_ApexPid, entityAddr + OFF_BLEEDOUT_STATE, extBuffer, sizeof(extBuffer))) {
            bleedoutState = *(int*)(extBuffer);
            isKnocked = (bleedoutState > 0);
            
            armorType = *(int*)(extBuffer + (OFF_ARMORTYPE - OFF_BLEEDOUT_STATE));
        }
    }
    
    
    void UpdateExtendedData() {
        UpdateExtendedDataBatch(address);
    }

    void CalculateDistance(const Vector3& localPos) {
        distance = position.Distance(localPos);
    }
    
    bool IsValidForESP(const Vector3& localPos, int localTeam, float maxDistance = 25000.0f) {
        if (!valid) return false;
        CalculateDistance(localPos);
        if (distance > maxDistance) return false;
        
        // 如果在训练场，显示所有有效实体（除了自己）
        if (g_IsInFiringRange) return true;
        
        if (team == localTeam && !isDummy) return false;
        return true;
    }

    Vector3 GetBonePosition(int boneIndex) {
        if (!address || !g_Driver) return Vector3();
        
        uintptr_t boneArray = 0;
        if (!g_Driver->ReadMemory(g_ApexPid, address + OFF_BONES, &boneArray, sizeof(boneArray)))
            return Vector3();
        
        struct Matrix3x4 { float m[3][4]; };
        Matrix3x4 boneMatrix;
        if (!g_Driver->ReadMemory(g_ApexPid, boneArray + (boneIndex * sizeof(Matrix3x4)), &boneMatrix, sizeof(boneMatrix)))
            return Vector3();
        
        return Vector3(boneMatrix.m[0][3], boneMatrix.m[1][3], boneMatrix.m[2][3]);
    }

    // 批量获取骨骼数据，减少 I/O
    bool GetBonePositions(const std::vector<int>& indices, std::vector<Vector3>& outPositions) {
        if (!address || !g_Driver) return false;
        
        uintptr_t boneArray = 0;
        if (!g_Driver->ReadMemory(g_ApexPid, address + OFF_BONES, &boneArray, sizeof(boneArray)))
            return false;

        // 对 boneArray 进行更宽松但安全的检查
        if (boneArray < 0x10000 || boneArray > 0x7FFFFFFFFFFF) 
            return false;

        // 找到最大索引以确定读取范围
        int maxIndex = 0;
        for (int idx : indices) if (idx > maxIndex) maxIndex = idx;
        
        if (maxIndex > 200) return false;

        struct Matrix3x4 { float m[3][4]; };
        size_t readSize = (maxIndex + 1) * sizeof(Matrix3x4);
        std::vector<Matrix3x4> tempBones(maxIndex + 1);

        if (!g_Driver->ReadMemory(g_ApexPid, boneArray, tempBones.data(), readSize))
            return false;

        outPositions.clear();
        for (int idx : indices) {
            if (idx > maxIndex) {
                outPositions.clear();
                return false;
            }
            Vector3 bonePos(tempBones[idx].m[0][3], tempBones[idx].m[1][3], tempBones[idx].m[2][3]);
            
            // 基础有效性检查：不应为全 0
            if (std::abs(bonePos.x) < 0.001f && std::abs(bonePos.y) < 0.001f && std::abs(bonePos.z) < 0.001f) {
                // 仅记录，不直接失败
                continue; 
            }
            outPositions.push_back(bonePos);
        }

        return outPositions.size() > 0;
    }
};




class EntityScanner {
private:
    static inline std::map<int, float> s_lastVisibleTimes;
    static inline int s_dummyIndices[100];
    static inline int s_dummyCount = 0;
    static inline bool s_scanned = false;

public:
    
    static bool CheckFiringRange() { return false; }

    static void ClearAll() {
        s_dummyCount = 0;
        s_scanned = false;
    }

    
    static void DoFullDummyScan() { }

    static std::vector<Entity> ScanEntities(int maxEntities = 100) {
        std::vector<Entity> entities;
        
        if (!g_Driver || !g_ApexPid || !g_ApexBase) {
            return entities;
        }

        // 获取当前游戏时间
        float curTime = 0.0f;
        uintptr_t globalVarsPtr = 0;
        if (g_Driver->ReadMemory(g_ApexPid, g_ApexBase + OFF_GLOBAL_VARS, &globalVarsPtr, sizeof(globalVarsPtr)) && globalVarsPtr) {
            g_Driver->ReadMemory(g_ApexPid, globalVarsPtr + 0x10, &curTime, sizeof(float));
        }
        
        Vector3 localPos;
        int localTeam = 0;
        uintptr_t localPlayer = 0;

        // 获取本地玩家基本信息
        g_Driver->ReadMemory(g_ApexPid, g_ApexBase + OFF_LOCAL_PLAYER, &localPlayer, sizeof(localPlayer));
        if (localPlayer > 0x10000 && localPlayer < 0x7FFFFFFFFFFF) {
            g_Driver->ReadMemory(g_ApexPid, localPlayer + OFF_LOCAL_ORIGIN, &localPos, sizeof(localPos));
            g_Driver->ReadMemory(g_ApexPid, localPlayer + OFF_TEAM_NUMBER, &localTeam, sizeof(localTeam));
        }

        uintptr_t entityListBase = g_ApexBase + OFF_ENTITY_LIST;

        // 优化：一次性批量读取 Entity List 所有的指针
        // 每个指针槽位间隔 32 字节 (1 << 5)
        int scanCount = (g_IsInFiringRange) ? 512 : maxEntities;
        if (scanCount < 100) scanCount = 100;
        if (scanCount > 512) scanCount = 512; // 恢复到合理范围，防止 I/O 阻塞

        size_t listBufferSize = scanCount * 32;
        std::vector<uint8_t> listBuffer(listBufferSize);
        
        if (!g_Driver->ReadMemory(g_ApexPid, entityListBase, listBuffer.data(), listBufferSize)) {
            return entities;
        }

        for (int i = 0; i < scanCount; ++i) {
            // 从批量读取的 buffer 中提取 entity 指针
            uintptr_t entityPtr = *(uintptr_t*)(listBuffer.data() + (i << 5));

            if (entityPtr < 0x10000 || entityPtr > 0x7FFFFFFFFFFF || entityPtr == localPlayer) {
                continue;
            }

            // 极简读取：先只读基本信息（坐标、血量、团队、可见性时间）
            // OFF_LOCAL_ORIGIN 是 0x17c, OFF_LAST_VISIBLE_TIME 是 0x1a54
            // 我们读取 0x1b00 确实包含了这些，但太大了。
            // 实际上我们可以只读取到 0x1b00，但对于每一个实体都读这么多会卡死。
            
            // 优化：只对“看起来像玩家”的实体进行读取
            // 先读一个很小的头信息（比如前 0x500 字节，包含坐标和团队）
            uint8_t baseBuffer[0x500];
            if (!g_Driver->ReadMemory(g_ApexPid, entityPtr, baseBuffer, sizeof(baseBuffer))) {
                continue;
            }

            Entity entity;
            entity.index = i;
            entity.address = entityPtr;
            entity.UpdateFromBuffer(baseBuffer, sizeof(baseBuffer));

            if (!entity.valid) continue;

            // 如果基本信息有效，再读可见性时间（单独读 4 字节，减少 I/O）
            g_Driver->ReadMemory(g_ApexPid, entityPtr + OFF_LAST_VISIBLE_TIME, &entity.lastVisibleTime, sizeof(float));

            // 可见性逻辑
            bool isVisibleNow = false;
            if (s_lastVisibleTimes.count(i)) {
                if (entity.lastVisibleTime > s_lastVisibleTimes[i]) {
                    isVisibleNow = true;
                }
            }
            
            if (!isVisibleNow && curTime > 0.1f) {
                isVisibleNow = (entity.lastVisibleTime + 0.1f > curTime);
            }
            entity.isVisible = isVisibleNow;
            s_lastVisibleTimes[i] = entity.lastVisibleTime;

            // 深度更新：仅对可见或极近的目标读取更多数据（血量、护甲、状态、骨骼）
            if (entity.isVisible || entity.distance < 8000.0f) {
                entity.UpdateExtendedDataBatch(entityPtr);
                
                // 批量读取骨骼 (如果开启了 ESP 骨骼)
                // 注意：这里需要一个全局或外部标志判断是否需要读取骨骼，
                // 但为了简化，我们只对可见目标读取。
                if (entity.isVisible) {
                    static const std::vector<int> boneIndices = {
                        8, 7, 3, 0,             // 0:Head, 1:Neck, 2:Chest, 3:Pelvis
                        11, 12, 13,             // 4:L_Shoulder, 5:L_Elbow, 6:L_Hand
                        34, 35, 36,             // 7:R_Shoulder, 8:R_Elbow, 9:R_Hand
                        18, 19, 20,             // 10:L_Hip, 11:L_Knee, 12:L_Foot
                        41, 42, 43              // 13:R_Hip, 14:R_Knee, 15:R_Foot
                    };
                    entity.hasBones = entity.GetBonePositions(boneIndices, entity.cachedBones);
                }

                // 训练场 Dummy 检查
                if (g_IsInFiringRange && !entity.isDummy) {
                    char nameBuf[32];
                    if (g_Driver->ReadMemory(g_ApexPid, entityPtr + OFF_SIGNIFIER_NAME, nameBuf, sizeof(nameBuf))) {
                        nameBuf[31] = '\0';
                        if (strstr(nameBuf, "dummie") || strstr(nameBuf, "npc")) {
                            entity.isDummy = true;
                        }
                    }
                }
            }
            
            entities.push_back(entity);
        }
        
        return entities;
    }
    
    
    static std::vector<Entity> ScanEntitiesBatch(int maxEntities = 64) {
        return ScanEntities(maxEntities);
    }
    
    
    static size_t GetCachedDummyCount() {
        return s_dummyCount;
    }
    
    
    static void ForceRescan() {
        s_scanned = false;
        s_dummyCount = 0;
    }
};
