#include "memory/simulated_reader.hpp"

#include <cstring>
#include <cmath>

SimulatedMemoryReader::~SimulatedMemoryReader() {
    Detach();
}

bool SimulatedMemoryReader::Initialize(size_t customSize) {
    const size_t sz = (customSize >= game_layout::kSimulatedMemorySize) ? customSize : game_layout::kSimulatedMemorySize;
    m_memory.assign(sz, 0);
    m_velocities.assign(game_layout::kMaxEntitySlots * 2, 0.0f);
    m_rngState = 0x12345678;

    auto offset = [this](uintptr_t off) {
        return reinterpret_cast<uint8_t*>(m_memory.data()) + off;
    };

    // 1. InGameState tại base + 0x100000
    auto* ig = reinterpret_cast<game_layout::InGameStateMemory*>(
        offset(game_layout::kInGameStateOffset));
    ig->magic = game_layout::kInGameMagic;
    ig->areaId = 1;
    ig->areaSeed = 13361591;
    ig->gameTick = 0;
    ig->playerStatePtr = m_base + game_layout::kPlayerStateOffset;
    ig->entityMapPtr = m_base + game_layout::kEntityMapOffset;
    ig->entityMapRoot = m_base + game_layout::kEntityMapOffset;

    // 2. PlayerState tại base + 0x110000
    auto* ps = reinterpret_cast<game_layout::PlayerStateMemory*>(
        offset(game_layout::kPlayerStateOffset));
    ps->posX = 0.0f; ps->posY = 0.0f; ps->posZ = 0.0f; ps->yaw = 0.0f;
    ps->currentHP = 1250; ps->maxHP = 1250;
    ps->currentMana = 300; ps->maxMana = 300;
    ps->currentES = 0; ps->maxES = 0;
    ps->currentSpirit = 100; ps->maxSpirit = 100;
    ps->currentWard = 0; ps->maxWard = 0;
    ps->movementFlags = 4; // Bit 2: Idle
    ps->debuffMask = 0;

    // 3. EntityMap tại base + 0x120000 (trống)
    auto* em = reinterpret_cast<game_layout::EntityMapMemory*>(
        offset(game_layout::kEntityMapOffset));
    em->capacity = game_layout::kMaxEntitySlots;
    em->count = 0;
    for (auto& e : em->entries) e = 0;

    // 4. Static pointer ".data" tại base + 0x300000 -> InGameState
    *reinterpret_cast<uint64_t*>(offset(game_layout::kInGameStatePtrStaticOffset)) =
        m_base + game_layout::kInGameStateOffset;

    // 5. CameraInstance tại base + 0x130000 (POE2 v0.5.5)
    auto* cam = reinterpret_cast<game_layout::CameraMemory*>(
        offset(game_layout::kCameraOffset));
    cam->vtable = 0x140001000ULL;
    cam->posX = 0.0f; cam->posY = 0.0f; cam->posZ = 0.0f;
    cam->targetX = 0.0f; cam->targetY = 0.0f; cam->targetZ = 0.0f;
    cam->pitch = -0.785f; cam->yaw = 0.0f; cam->roll = 0.0f;
    cam->currentDistance = 40.0f;
    cam->minDistance = 15.0f;
    cam->maxDistance = 45.0f;
    cam->fieldOfView = 0.785f;
    cam->zNear = 1.0f;
    cam->zFar = 150.0f;
    cam->zoomSmoothingSpeed = 5.0f;

    // 6. FogMemory tại base + 0x130100 (POE2 v0.5.5)
    auto* fog = reinterpret_cast<game_layout::FogMemory*>(
        offset(game_layout::kFogOffset));
    fog->fogDensity = 1.0f;
    fog->fogStartDistance = 50.0f;
    fog->fogEndDistance = 200.0f;
    fog->heightFalloff = 0.1f;

    return true;
}

void SimulatedMemoryReader::EnsureSize(size_t minSize) {
    if (m_memory.size() < minSize) {
        m_memory.resize(minSize, 0);
    }
}

bool SimulatedMemoryReader::Attach(uint32_t pid) {
    if (m_memory.empty()) return false; // phải Initialize() trước
    m_pid = pid;
    return true;
}

void SimulatedMemoryReader::Detach() {
    m_pid = 0;
}

bool SimulatedMemoryReader::Read(uintptr_t address, void* buffer, size_t size) {
    if (!m_pid || !buffer || size == 0) return false;

    // Địa chỉ phải nằm trong khối module ảo
    if (address < m_base) return false;
    const size_t offset = static_cast<size_t>(address - m_base);
    if (offset + size > m_memory.size()) return false;

    std::memcpy(buffer, m_memory.data() + offset, size);
    return true;
}

bool SimulatedMemoryReader::Write(uintptr_t address, const void* buffer, size_t size) {
    if (!m_pid || !buffer || size == 0 || m_memory.empty()) return false;

    if (address < m_base) return false;
    const size_t offset = static_cast<size_t>(address - m_base);
    if (offset + size > m_memory.size()) return false;

    std::memcpy(m_memory.data() + offset, buffer, size);
    return true;
}

bool SimulatedMemoryReader::ForEachReadableRegion(const RegionFn& fn) {
    if (m_memory.empty() || !m_pid) return false;
    // Toàn bộ module ảo là 1 region readable duy nhất
    return fn(m_base, m_memory.size());
}

bool SimulatedMemoryReader::ForEachHeapRegion(const RegionFn& fn) {
    return ForEachReadableRegion(fn);
}

uint32_t SimulatedMemoryReader::NextRandom() {
    m_rngState = m_rngState * 1664525u + 1013904223u;
    return m_rngState;
}

game_layout::InGameStateMemory* SimulatedMemoryReader::InGame() {
    if (m_memory.empty()) return nullptr;
    return reinterpret_cast<game_layout::InGameStateMemory*>(
        m_memory.data() + game_layout::kInGameStateOffset);
}

game_layout::PlayerStateMemory* SimulatedMemoryReader::Player() {
    if (m_memory.empty()) return nullptr;
    return reinterpret_cast<game_layout::PlayerStateMemory*>(
        m_memory.data() + game_layout::kPlayerStateOffset);
}

game_layout::EntityMapMemory* SimulatedMemoryReader::EntityMap() {
    if (m_memory.empty()) return nullptr;
    return reinterpret_cast<game_layout::EntityMapMemory*>(
        m_memory.data() + game_layout::kEntityMapOffset);
}

game_layout::CameraMemory* SimulatedMemoryReader::Camera() {
    if (m_memory.empty()) return nullptr;
    return reinterpret_cast<game_layout::CameraMemory*>(
        m_memory.data() + game_layout::kCameraOffset);
}

game_layout::FogMemory* SimulatedMemoryReader::Fog() {
    if (m_memory.empty()) return nullptr;
    return reinterpret_cast<game_layout::FogMemory*>(
        m_memory.data() + game_layout::kFogOffset);
}

uint32_t SimulatedMemoryReader::SpawnEntity(const game_layout::EntityMemory& tmpl) {
    auto* em = EntityMap();
    if (!em) return UINT32_MAX;

    // Tìm slot trống (entries[i] == 0)
    for (uint32_t i = 0; i < em->capacity && i < game_layout::kMaxEntitySlots; ++i) {
        if (em->entries[i] != 0) continue;

        const uintptr_t entityAddr = m_base + game_layout::kEntitiesOffset
            + static_cast<size_t>(i) * sizeof(game_layout::EntityMemory);
        auto* entity = reinterpret_cast<game_layout::EntityMemory*>(
            m_memory.data() + game_layout::kEntitiesOffset
            + static_cast<size_t>(i) * sizeof(game_layout::EntityMemory));
        std::memcpy(entity, &tmpl, sizeof(game_layout::EntityMemory));

        // Tính khoảng cách ban đầu tới player (như Tick() vẫn làm)
        const auto* ps = Player();
        const float dx = entity->posX - ps->posX;
        const float dy = entity->posY - ps->posY;
        entity->distanceToPlayer = std::sqrt(dx * dx + dy * dy);

        em->entries[i] = entityAddr;
        if (i >= em->count) em->count = i + 1;

        // Vận tốc ngẫu nhiên nhỏ cho mô phỏng di chuyển
        // (ép sang signed TRƯỚC khi trừ để tránh unsigned underflow)
        m_velocities[i * 2] = (static_cast<float>(static_cast<int>(NextRandom() % 200)) - 100.0f) / 100.0f;
        m_velocities[i * 2 + 1] = (static_cast<float>(static_cast<int>(NextRandom() % 200)) - 100.0f) / 100.0f;
        return i;
    }
    return UINT32_MAX; // Đầy slot
}

void SimulatedMemoryReader::Tick(float dtSeconds) {
    if (!m_autoSimulate) return;
    auto* ig = InGame();
    auto* ps = Player();
    auto* em = EntityMap();
    if (!ig || !ps || !em) return;

    ++ig->gameTick;
    const float tick = static_cast<float>(ig->gameTick);

    // HP nhân vật dao động hình sin (55% - 100%) - mô phỏng giao tranh
    ps->currentHP = static_cast<uint32_t>(
        static_cast<float>(ps->maxHP) * (0.55f + 0.45f * std::sin(tick * 0.02f)));

    // Mana hồi từ từ
    if (ps->currentMana < ps->maxMana) ++ps->currentMana;

    // Người chơi đi bộ chậm quanh tâm bản đồ
    ps->posX = 30.0f * std::sin(tick * 0.003f);
    ps->posY = 30.0f * std::cos(tick * 0.002f);

    // Entity di chuyển + cập nhật khoảng cách + stagger boss
    for (uint32_t i = 0; i < em->capacity && i < game_layout::kMaxEntitySlots; ++i) {
        if (em->entries[i] == 0) continue;
        auto* ent = reinterpret_cast<game_layout::EntityMemory*>(
            m_memory.data() + game_layout::kEntitiesOffset
            + static_cast<size_t>(i) * sizeof(game_layout::EntityMemory));
        if (ent->magic != game_layout::kEntityMagic) continue;
        if (ent->extraFlags & game_layout::kEntityFlagDead) continue;

        const float vx = m_velocities[i * 2];
        const float vy = m_velocities[i * 2 + 1];
        ent->posX += vx * dtSeconds;
        ent->posY += vy * dtSeconds;

        // Đổi hướng khi đi quá xa tâm
        if (std::fabs(ent->posX) > 100.0f) m_velocities[i * 2] = -vx;
        if (std::fabs(ent->posY) > 100.0f) m_velocities[i * 2 + 1] = -vy;

        const float dx = ent->posX - ps->posX;
        const float dy = ent->posY - ps->posY;
        ent->distanceToPlayer = std::sqrt(dx * dx + dy * dy);

        // Boss: stagger chạy vòng tròn 0-10000 theo tick
        if (ent->extraFlags & game_layout::kEntityFlagBoss) {
            ent->staggerProgress = static_cast<uint16_t>(
                static_cast<uint32_t>(tick * 50.0f) % 10001);
        }
    }
}