#include "input/humanized_input_arbiter.hpp"
#include <thread>
#include <chrono>

namespace input {

HumanizedInputArbiter::HumanizedInputArbiter(const HumanizedInputConfig& config)
    : m_config(config),
      m_mode(config.defaultMode) {}

void HumanizedInputArbiter::GenerateTrajectory(
    Vector2D start,
    Vector2D target,
    common::TrajectoryBuffer& outBuf,
    int steps
) {
    if (m_mode == MouseTrajectoryMode::CubicBezierClassic) {
        const int s = (steps > 0) ? steps : 25;
        m_cubicGen.GenerateTrajectory(start, target, outBuf, s, true);
    } else {
        m_quinticCtrl.GenerateTrajectory(start, target, outBuf, steps);
    }
}

bool HumanizedInputArbiter::MoveMouseSmooth(
    KMBoxNet& kmbox,
    int targetX,
    int targetY,
    int steps,
    int stepDelayMs
) {
    // KHÓA AN TOÀN BẤT BIẾN: Game không ở tiền cảnh -> Tuyệt đối cấm gửi tín hiệu chuột (INV-FOCUS-INTERLOCK-HARDWARE-SAFETY)
    if (!kmbox.IsGameWindowFocused()) {
        return false;
    }

    POINT curPt{};
    GetCursorPos(&curPt);

    if (std::abs(targetX - curPt.x) < 2 && std::abs(targetY - curPt.y) < 2) {
        return true;
    }

    const Vector2D startPos{ static_cast<float>(curPt.x), static_cast<float>(curPt.y) };
    const Vector2D targetPos{ static_cast<float>(targetX), static_cast<float>(targetY) };
    common::TrajectoryBuffer trajectory;
    GenerateTrajectory(startPos, targetPos, trajectory, steps);

    if (kmbox.IsEmulationMode()) {
        float currX = startPos.x;
        float currY = startPos.y;
        for (const auto& step : trajectory) {
            // Tái kiểm tra focus giữa các bước để ngắt lập tức nếu người dùng Alt+Tab
            if (!kmbox.IsGameWindowFocused()) {
                return false;
            }
            currX += step.x;
            currY += step.y;
            SetCursorPos(static_cast<int>(std::round(currX)), static_cast<int>(std::round(currY)));
            if (stepDelayMs > 0) {
                std::this_thread::sleep_for(std::chrono::milliseconds(stepDelayMs));
            }
        }
        SetCursorPos(targetX, targetY);
    } else {
        for (const auto& step : trajectory) {
            if (!kmbox.IsGameWindowFocused()) {
                return false;
            }
            kmbox.MoveMouse(static_cast<short>(step.x), static_cast<short>(step.y));
            if (stepDelayMs > 0) {
                std::this_thread::sleep_for(std::chrono::milliseconds(stepDelayMs));
            }
        }
        POINT endPt{};
        GetCursorPos(&endPt);
        const short remX = static_cast<short>(targetX - endPt.x);
        const short remY = static_cast<short>(targetY - endPt.y);
        if (remX != 0 || remY != 0) {
            kmbox.MoveMouse(remX, remY);
        }
    }

    return true;
}

int HumanizedInputArbiter::GenerateDwellTimeMs(float meanMs, float stdDevMs) {
    if (m_mode == MouseTrajectoryMode::QuinticBezierStealth) {
        return m_quinticCtrl.GenerateDwellTimeMs(meanMs, stdDevMs);
    }
    return m_cubicGen.GenerateDwellTimeMs(meanMs, stdDevMs);
}

bool HumanizedInputArbiter::ClickMouseHumanized(
    KMBoxNet& kmbox,
    int button,
    float meanMs,
    float stdDevMs
) {
    if (!kmbox.IsGameWindowFocused()) {
        return false; // INV-FOCUS-INTERLOCK-HARDWARE-SAFETY
    }

    const int dwellTime = GenerateDwellTimeMs(meanMs, stdDevMs);
    return kmbox.ClickMouse(button, dwellTime);
}

KinematicProfile HumanizedInputArbiter::AnalyzeTrajectory(
    const common::TrajectoryBuffer& traj,
    float stepDurationSec
) {
    KinematicProfile prof{};
    const size_t n = traj.size();
    if (n < 3 || stepDurationSec <= 0.0f) {
        return prof;
    }

    const float dt = stepDurationSec;
    const float invDt = 1.0f / dt;

    // 1. Tính toán vận tốc tại từng bước: V_i = ||dPos_i|| / dt
    float prevVel = 0.0f;
    float prevAcc = 0.0f;

    for (size_t i = 0; i < n; ++i) {
        const float stepLen = std::sqrt(traj[i].x * traj[i].x + traj[i].y * traj[i].y);
        const float curVel = stepLen * invDt;
        if (curVel > prof.maxVelocity) {
            prof.maxVelocity = curVel;
        }

        if (i >= 1) {
            // Gia tốc vi phân: A_i = (V_i - V_{i-1}) / dt
            const float curAcc = (curVel - prevVel) * invDt;
            const float absAcc = std::abs(curAcc);
            if (absAcc > prof.maxAcceleration) {
                prof.maxAcceleration = absAcc;
            }

            if (i == 1) {
                prof.startAcceleration = curAcc;
            }
            if (i == n - 1) {
                prof.endAcceleration = curAcc;
            }

            if (i >= 2) {
                // Độ giật vi phân (Jerk): J_i = (A_i - A_{i-1}) / dt
                const float curJerk = (curAcc - prevAcc) * invDt;
                const float absJerk = std::abs(curJerk);
                if (absJerk > prof.maxJerk) {
                    prof.maxJerk = absJerk;
                }
                prof.totalJerkCost += (curJerk * curJerk) * dt;
            }
            prevAcc = curAcc;
        }
        prevVel = curVel;
    }

    prof.isJerkBounded = (prof.maxJerk <= 2.5e7f);
    return prof;
}

} // namespace input
