#include "navigation/movement_controller.hpp"
#include "common/window_utils.hpp"
#include <cmath>

namespace navigation {

MovementController::MovementController(const MovementConfig& config)
    : m_config(config) {
}

void MovementController::Stop(KMBoxNet& kmbox) {
    if (!m_heldVks.empty()) {
        for (uint8_t vk : m_heldVks) {
            kmbox.KeyUpVk(vk);
        }
        m_heldVks.clear();
    }
    if (m_isMoveOnlyActive) {
        kmbox.KeyUpVk(m_config.moveOnlyVk);
        m_isMoveOnlyActive = false;
    }
    m_currentWasd = common::WasdVector{};
}

bool MovementController::SteerTowards(float dx, float dy, KMBoxNet& kmbox, uint64_t nowMs) {
    if (!kmbox.IsGameWindowFocused()) {
        Stop(kmbox);
        return false;
    }

    const float len = std::sqrt(dx * dx + dy * dy);
    if (len < 0.001f) {
        Stop(kmbox);
        return false;
    }

    if (m_config.mode == MovementMode::MOUSE) {
        return SteerMoveOnly(dx, dy, kmbox, nowMs);
    } else {
        return SteerWasd(dx, dy, kmbox, nowMs);
    }
}

bool MovementController::SteerWasd(float dx, float dy, KMBoxNet& kmbox, uint64_t nowMs) {
    // Ngắt chế độ Move-Only nếu trước đó đang bật
    if (m_isMoveOnlyActive) {
        kmbox.KeyUpVk(m_config.moveOnlyVk);
        m_isMoveOnlyActive = false;
    }

    const common::WasdVector wasd = common::WorldToWasd(dx, dy);
    if (wasd.empty()) {
        Stop(kmbox);
        return false;
    }

    common::WasdKeyArray newVks;
    if (wasd.up) {
        newVks.push_back(0x57); // 'W'
        if (m_config.pulseEWithForward) {
            if (nowMs == 0 || nowMs - m_lastPulseEMs >= 800) {
                m_lastPulseEMs = nowMs;
                newVks.push_back(0x45); // 'E'
            }
        }
    }
    if (wasd.down)  newVks.push_back(0x53); // 'S'
    if (wasd.left)  newVks.push_back(0x41); // 'A'
    if (wasd.right) newVks.push_back(0x44); // 'D'

    if (newVks.empty()) {
        Stop(kmbox);
        return false;
    }

    // 1. Nếu hướng đang giữ đã khớp hoàn toàn -> DUY TRÌ LIÊN TỤC (0ms overhead, không sleep!)
    if (newVks == m_heldVks) {
        return true;
    }

    // 2. INV-WASD-MIN-DWELL: Khi đang giữ hướng, giữ tối thiểu wasdMinDwellMs trước khi đổi hướng
    // để loại bỏ micro-jitter khi vector nằm ở ranh giới giữa 2 hướng 45 độ.
    if (!m_heldVks.empty() && nowMs > 0 && (nowMs - m_lastDirectionChangeMs < m_config.wasdMinDwellMs)) {
        return true;
    }
    m_lastDirectionChangeMs = nowMs;

    // 3. Đổi hướng mượt mà: Nhả các phím không còn thuộc hướng mới, nhấn các phím mới
    for (size_t i = 0; i < m_heldVks.size(); ++i) {
        const uint8_t oldVk = m_heldVks[i];
        if (!newVks.contains(oldVk)) {
            kmbox.KeyUpVk(oldVk);
        }
    }
    for (size_t i = 0; i < newVks.size(); ++i) {
        const uint8_t newVk = newVks[i];
        if (!m_heldVks.contains(newVk)) {
            kmbox.KeyDownVk(newVk);
        }
    }

    m_heldVks = newVks;
    m_currentWasd = wasd;
    return true;
}

bool MovementController::SteerMoveOnly(float dx, float dy, KMBoxNet& kmbox, uint64_t nowMs) {
    // Ngắt phím WASD nếu trước đó đang giữ
    if (!m_heldVks.empty()) {
        for (uint8_t vk : m_heldVks) {
            kmbox.KeyUpVk(vk);
        }
        m_heldVks.clear();
        m_currentWasd = common::WasdVector{};
    }

    int screenW = 0;
    int screenH = 0;
    common::GetGameResolution(screenW, screenH);
    if (screenW <= 0 || screenH <= 0) {
        screenW = 1920;
        screenH = 1080;
    }

    const float dist = (std::min)(static_cast<float>(screenH) * 0.40f, m_config.mouseMaxScreenDist);
    const auto target = common::WorldToScreenIsometric(dx, dy, dist, static_cast<float>(screenW), static_cast<float>(screenH), 80.0f);

    // Di chuyển con trỏ chuột mượt theo hướng waypoint
    kmbox.MoveMouseSmooth(static_cast<int>(target.x), static_cast<int>(target.y), m_curveGen, 10, 1);

    // Giữ hoặc pulse phím Move-Only chuẩn ExiledBot 2 (mặc định 'T')
    if (!m_isMoveOnlyActive) {
        kmbox.KeyDownVk(m_config.moveOnlyVk);
        m_isMoveOnlyActive = true;
        m_lastMousePulseMs = nowMs;
    } else if (nowMs - m_lastMousePulseMs >= m_config.mousePulseIntervalMs) {
        // Duy trì trạng thái KeyDown để nhân vật chạy liên tục
        kmbox.KeyDownVk(m_config.moveOnlyVk);
        m_lastMousePulseMs = nowMs;
    }

    return true;
}

} // namespace navigation
