#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <cstdint>
#include <vector>
#include <cmath>
#include <string>
#include "memory/imemory_reader.hpp"

namespace memory {

// Cấu trúc dữ liệu địa hình gốc trích xuất từ RAM của POE2
struct NativeTerrainData {
    uint32_t cols = 0;                  // Chiều ngang (số cột)
    uint32_t rows = 0;                  // Chiều dọc (số hàng)
    uint32_t bytesPerRow = 0;           // Bước nhảy bộ nhớ (pitch)
    float gridToWorldScale = 10.875f;   // Hệ số nhân chuyển đổi sang tọa độ thế giới (PoE units)
    float worldOriginX = 0.0f;          // Điểm gốc thế giới X
    float worldOriginY = 0.0f;          // Điểm gốc thế giới Y
    std::vector<uint8_t> walkability;   // Ma trận 2D (0 = Blocked/Tường, >0 = Walkable/Đất)

    bool IsValid() const {
        return cols >= 50 && cols <= 4000 && rows >= 50 && rows <= 4000 &&
               walkability.size() == static_cast<size_t>(cols) * rows;
    }

    bool IsWalkableGrid(uint32_t gx, uint32_t gy) const {
        if (gx >= cols || gy >= rows) return false;
        return walkability[static_cast<size_t>(gy) * cols + gx] != 0;
    }

    bool IsWalkableWorld(float wx, float wy) const {
        uint32_t gx = 0, gy = 0;
        if (!WorldToGrid(wx, wy, gx, gy)) return false;
        return IsWalkableGrid(gx, gy);
    }

    bool WorldToGrid(float wx, float wy, uint32_t& outGx, uint32_t& outGy) const {
        if (gridToWorldScale <= 0.001f) return false;
        const float localX = (wx - worldOriginX) / gridToWorldScale;
        const float localY = (wy - worldOriginY) / gridToWorldScale;
        if (localX < 0.0f || localY < 0.0f) return false;
        outGx = static_cast<uint32_t>(localX);
        outGy = static_cast<uint32_t>(localY);
        return outGx < cols && outGy < rows;
    }

    bool GridToWorld(uint32_t gx, uint32_t gy, float& outWx, float& outWy) const {
        if (gx >= cols || gy >= rows) return false;
        outWx = worldOriginX + (static_cast<float>(gx) + 0.5f) * gridToWorldScale;
        outWy = worldOriginY + (static_cast<float>(gy) + 0.5f) * gridToWorldScale;
        return true;
    }

    float WalkablePercentage() const {
        if (walkability.empty()) return 0.0f;
        size_t walkableCount = 0;
        for (uint8_t v : walkability) {
            if (v != 0) ++walkableCount;
        }
        return (static_cast<float>(walkableCount) / static_cast<float>(walkability.size())) * 100.0f;
    }
};

class TerrainReader {
public:
    TerrainReader() = default;

    // Trích xuất TerrainData từ địa chỉ cấu trúc Terrain hoặc AreaInstance
    // Sử dụng phân tích bố cục StdVector / Raw Buffer của PoE engine
    static bool ExtractFromTerrainStruct(
        IMemoryReader& reader,
        uintptr_t terrainStructAddr,
        NativeTerrainData& outTerrain
    );

    // Quét tìm cấu trúc TerrainData xung quanh địa chỉ cơ sở (AreaInstance hoặc Player Entity)
    static bool ScanTerrainCandidates(
        IMemoryReader& reader,
        uintptr_t baseAddr,
        size_t searchRangeBytes,
        NativeTerrainData& outTerrain
    );

    // Giải mã mảng byte thô từ bộ nhớ game thành ma trận 2D chuẩn hóa
    // Hỗ trợ cả 2 dạng: 1 byte per tile hoặc 4 bits / 2 tiles per byte
    static bool DecodeWalkableBuffer(
        const uint8_t* rawData,
        size_t rawSize,
        uint32_t cols,
        uint32_t rows,
        uint32_t bytesPerRow,
        std::vector<uint8_t>& outWalkability
    );
};

} // namespace memory
