#include "mouse.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <memory>

// 静态成员初始化
std::thread MousePlugin::s_listenThread;
std::mutex MousePlugin::s_mutex;
std::atomic<bool> MousePlugin::s_isListening(false);
int MousePlugin::s_lastX = 0;
int MousePlugin::s_lastY = 0;

// Windows平台
#ifdef _WIN32
#include <windows.h>
#define MOUSE_LEFT 0
#define MOUSE_RIGHT 1
#define MOUSE_MIDDLE 2

void MousePlugin::PlatformMove(int x, int y) {
    SetCursorPos(x, y);
}

void MousePlugin::PlatformGetPosition(int& x, int& y) {
    POINT pt;
    GetCursorPos(&pt);
    x = pt.x;
    y = pt.y;
}

void MousePlugin::PlatformClick(int button, bool isDown) {
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    if (button == MOUSE_LEFT)
        input.mi.dwFlags = isDown ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
    else if (button == MOUSE_RIGHT)
        input.mi.dwFlags = isDown ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
    else if (button == MOUSE_MIDDLE)
        input.mi.dwFlags = isDown ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
    SendInput(1, &input, sizeof(INPUT));
}

void MousePlugin::PlatformScroll(int dx, int dy) {
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_WHEEL;
    input.mi.mouseData = dy * 120;
    SendInput(1, &input, sizeof(INPUT));
}

// macOS平台
#elif __APPLE__
#include <ApplicationServices/ApplicationServices.h>
#define MOUSE_LEFT 0
#define MOUSE_RIGHT 1
#define MOUSE_MIDDLE 2

void MousePlugin::PlatformMove(int x, int y) {
    CGEventRef e = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, CGPointMake(x, y), kCGMouseButtonLeft);
    CGEventPost(kCGHIDEventTap, e);
    CFRelease(e);
}

void MousePlugin::PlatformGetPosition(int& x, int& y) {
    CGPoint pt = CGEventGetLocation(CGEventCreate(NULL));
    x = (int)pt.x;
    y = (int)pt.y;
}

void MousePlugin::PlatformClick(int button, bool isDown) {
    CGEventType t = isDown ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
    if (button == MOUSE_RIGHT) t = isDown ? kCGEventRightMouseDown : kCGEventRightMouseUp;
    if (button == MOUSE_MIDDLE) t = isDown ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
    CGEventRef e = CGEventCreateMouseEvent(NULL, t, CGEventGetLocation(CGEventCreate(NULL)), (CGMouseButton)button);
    CGEventPost(kCGHIDEventTap, e);
    CFRelease(e);
}

void MousePlugin::PlatformScroll(int dx, int dy) {
    CGEventRef e = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 2, dy, dx);
    CGEventPost(kCGHIDEventTap, e);
    CFRelease(e);
}

// Linux平台
#elif __linux__
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#define MOUSE_LEFT 1
#define MOUSE_RIGHT 3
#define MOUSE_MIDDLE 2

Display* display = XOpenDisplay(NULL);

void MousePlugin::PlatformMove(int x, int y) {
    XWarpPointer(display, None, DefaultRootWindow(display), 0,0,0,0, x,y);
    XFlush(display);
}

void MousePlugin::PlatformGetPosition(int& x, int& y) {
    Window root, child;
    int rx, ry;
    unsigned int mask;
    XQueryPointer(display, DefaultRootWindow(display), &root, &child, &rx, &ry, &x, &y, &mask);
}

void MousePlugin::PlatformClick(int button, bool isDown) {
    XTestFakeButtonEvent(display, button, isDown, CurrentTime);
    XFlush(display);
}

void MousePlugin::PlatformScroll(int dx, int dy) {
    XTestFakeRelativeMotionEvent(display, 0, dy*10, CurrentTime);
    XFlush(display);
}

#endif

// 基础方法
Napi::Value MousePlugin::Move(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber()) {
        Napi::TypeError::New(env, "需要x,y数字参数").ThrowAsJavaScriptException();
        return env.Null();
    }
    int x = info[0].As<Napi::Number>().Int32Value();
    int y = info[1].As<Napi::Number>().Int32Value();
    PlatformMove(x, y);
    return env.Undefined();
}

Napi::Value MousePlugin::GetPosition(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    int x, y;
    PlatformGetPosition(x, y);
    Napi::Object obj = Napi::Object::New(env);
    obj.Set("x", x);
    obj.Set("y", y);
    return obj;
}

Napi::Value MousePlugin::Click(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    if (info.Length() < 1 || !info[0].IsNumber()) {
        Napi::TypeError::New(env, "需要按钮参数").ThrowAsJavaScriptException();
        return env.Null();
    }
    int btn = info[0].As<Napi::Number>().Int32Value();
    PlatformClick(btn, true);
    PlatformClick(btn, false);
    return env.Undefined();
}

Napi::Value MousePlugin::Scroll(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber()) {
        Napi::TypeError::New(env, "需要dx,dy参数").ThrowAsJavaScriptException();
        return env.Null();
    }
    int dx = info[0].As<Napi::Number>().Int32Value();
    int dy = info[1].As<Napi::Number>().Int32Value();
    PlatformScroll(dx, dy);
    return env.Undefined();
}

// 监听循环（适配你的回调）
void MousePlugin::ListenLoop(Napi::ThreadSafeFunction tsfn) {
    int lastX = 0, lastY = 0;
    PlatformGetPosition(lastX, lastY);
    
    while (s_isListening) {
        int cx, cy;
        PlatformGetPosition(cx, cy);
        
        if (cx != lastX || cy != lastY) {
            lastX = cx;
            lastY = cy;
            
            // 分配坐标数据
            auto* pos = new std::pair<int, int>(cx, cy);
            
            // 线程安全调用JS回调（关键修复）
            tsfn.BlockingCall(
                pos,
                [](Napi::Env env, Napi::Function jsCallback, std::pair<int, int>* data) {
                    // 创建HandleScope（必须）
                    Napi::HandleScope scope(env);
                    // 创建坐标对象
                    Napi::Object xy = Napi::Object::New(env);
                    xy.Set("x", data->first);
                    xy.Set("y", data->second);
                    // 调用你的回调函数
                    jsCallback.Call({xy});
                    // 释放内存
                    delete data;
                }
            );
        }
        
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
    
    // 释放线程安全函数
    tsfn.Release();
}

// 启动监听（完全支持你的回调语法）
Napi::Value MousePlugin::start(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    std::lock_guard<std::mutex> lock(s_mutex);

    // 必须传入回调函数（你的代码有）
    if (info.Length() < 1 || !info[0].IsFunction()) {
        Napi::TypeError::New(env, "必须传入鼠标移动回调函数").ThrowAsJavaScriptException();
        return env.Null();
    }

    if (s_isListening) {
        Napi::Error::New(env, "已在监听").ThrowAsJavaScriptException();
        return env.Null();
    }

    // 创建线程安全函数
    Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
        env,
        info[0].As<Napi::Function>(),
        "MouseMoveCallback",
        0,
        1
    );

    // 启动监听
    s_isListening = true;
    s_listenThread = std::thread(&MousePlugin::ListenLoop, tsfn);

    return env.Undefined();
}

// 停止监听
Napi::Value MousePlugin::stop(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    std::lock_guard<std::mutex> lock(s_mutex);

    if (!s_isListening) {
        Napi::Error::New(env, "未监听").ThrowAsJavaScriptException();
        return env.Null();
    }

    s_isListening = false;
    if (s_listenThread.joinable()) {
        s_listenThread.join();
    }

    return env.Undefined();
}

// 导出方法
Napi::Object MousePlugin::Init(Napi::Env env, Napi::Object exports) {
    Napi::Object mouse = Napi::Object::New(env);
    mouse.Set("move", Napi::Function::New(env, Move));
    mouse.Set("get", Napi::Function::New(env, GetPosition));
    mouse.Set("click", Napi::Function::New(env, Click));
    mouse.Set("scroll", Napi::Function::New(env, Scroll));
    mouse.Set("start", Napi::Function::New(env, start));
    mouse.Set("stop", Napi::Function::New(env, stop));
    exports.Set("mouse", mouse);
    return exports;
}