#include <iostream>
#include <windows.h>
#include <iomanip>
#include <vector>
#include <string>
#include <cwchar>
#include <sstream>
#include <locale>
#include <chrono>
#include <thread>
#include <cmath>
#include <stdexcept>
#include <cstdio>
#include <memory>
#include <array>
#include <map>

using namespace std;

float dpi = -1;

//通用数据结构体
struct Data {
    bool success;
    string message;
};

//坐标结构体
struct Coord {
    int x;
    int y;
};

//获取DPI缩放比例
float GetDPIScale() {
    // 方法1：使用GetDpiForWindow（Windows 10 1607+）
    static float cachedScale = 0.0f;
    
    if (cachedScale == 0.0f) {
        HMODULE hUser32 = LoadLibraryW(L"user32.dll");
        if (hUser32) {
            typedef UINT(WINAPI* GetDpiForWindowFunc)(HWND);
            GetDpiForWindowFunc pGetDpiForWindow = 
                (GetDpiForWindowFunc)GetProcAddress(hUser32, "GetDpiForWindow");
            
            if (pGetDpiForWindow) {
                // 获取主窗口的DPI
                UINT dpi = pGetDpiForWindow(GetDesktopWindow());
                if (dpi > 0) {
                    cachedScale = static_cast<float>(dpi) / 96.0f;
                    FreeLibrary(hUser32);
                    return cachedScale;
                }
            }
            FreeLibrary(hUser32);
        }
        
        // 方法2：使用SystemParametersInfo
        HDC hdc = GetDC(NULL);
        if (hdc) {
            // 获取真实的DPI
            int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
            ReleaseDC(NULL, hdc);
            
            // 系统可能返回96（虚拟化DPI），所以需要进一步验证
            if (dpiX > 96) {
                cachedScale = static_cast<float>(dpiX) / 96.0f;
                return cachedScale;
            }
        }
        
        // 方法3：检查注册表（作为后备）
        HKEY hKey;
        if (RegOpenKeyExW(HKEY_CURRENT_USER, 
                        L"Control Panel\\Desktop\\WindowMetrics", 
                        0, KEY_READ, &hKey) == ERROR_SUCCESS) {
            DWORD value;
            DWORD size = sizeof(DWORD);
            
            // 检查AppliedDPI设置
            if (RegQueryValueExW(hKey, L"AppliedDPI", NULL, NULL, 
                               (LPBYTE)&value, &size) == ERROR_SUCCESS) {
                cachedScale = static_cast<float>(value) / 96.0f;
            } else {
                // 默认回退值
                cachedScale = 1.0f;
            }
            RegCloseKey(hKey);
        } else {
            cachedScale = 1.0f;
        }
    }
    
    return cachedScale;
}

//根据DPI将逻辑坐标转为绝对坐标
int dx(int x){
    return x*dpi;
}
int dy(int y){
    return y*dpi;
}

//根据DPI将绝对坐标转为逻辑坐标
int lx(int x){
    return x/dpi;
}
int ly(int y){
    return y/dpi;
}

//移动鼠标到指定位置
void MoveMouseTo(int x, int y) {
    SetCursorPos(lx(x), ly(y));
    cout<<"[INFO]模拟鼠标移动成功\n\n";
}

//模拟鼠标左键点击
void SimulateMouseClick() {
    INPUT inputs[2] = {};
    inputs[0].type = INPUT_MOUSE;
    inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    inputs[1].type = INPUT_MOUSE;
    inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(2, inputs, sizeof(INPUT));
    cout<<"[INFO]模拟点击成功\n\n";
}

//模拟鼠标左键按下
void MouseLeftDown() {
    INPUT input = {};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &input, sizeof(INPUT));
    cout<<"[INFO]模拟鼠标按下成功\n\n";
}

//模拟鼠标左键抬起
void MouseLeftUp() {
    INPUT input = {};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &input, sizeof(INPUT));
    cout<<"[INFO]模拟鼠标抬起成功\n\n";
}

//获取鼠标当前坐标
Coord GetCurrentMouseCoord() {
    POINT pt;
    GetCursorPos(&pt);
    Coord result;
    result.x = dx(pt.x);
    result.y = dy(pt.y);
    return result;
}

//模拟单个按键
void SimulateKeyPress(WORD vkCode, bool extended = false) {
    INPUT inputs[2] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = vkCode;
    inputs[0].ki.dwFlags = (extended ? KEYEVENTF_EXTENDEDKEY : 0);
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = vkCode;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP | (extended ? KEYEVENTF_EXTENDEDKEY : 0);
    SendInput(2, inputs, sizeof(INPUT));
}

//模拟组合键
void SimulateHotkey(WORD vk1, WORD vk2) {
    INPUT inputs[4] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = vk1;
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = vk2;
    inputs[2].type = INPUT_KEYBOARD;
    inputs[2].ki.wVk = vk2;
    inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
    inputs[3].type = INPUT_KEYBOARD;
    inputs[3].ki.wVk = vk1;
    inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(4, inputs, sizeof(INPUT));
}

//UTF-8转UTF-16
wstring UTF8ToWide(const string& utf8Str) {
    if (utf8Str.empty()) return L"";
    
    int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), 
                                       static_cast<int>(utf8Str.length()), 
                                       nullptr, 0);
    if (wideLen == 0) return L"";
    
    wstring wideStr(wideLen, 0);
    MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), 
                        static_cast<int>(utf8Str.length()), 
                        &wideStr[0], wideLen);
    
    return wideStr;
}

//模拟输入字符串
void SendUnicodeTextW(const wstring& text) {
    if (text.empty()) return;
    INPUT input = {0};
    input.type = INPUT_KEYBOARD;
    for (wchar_t ch : text) {
        input.ki.wScan = ch;
        input.ki.time = 0;
        input.ki.dwExtraInfo = 0;
        input.ki.wVk = 0;
        input.ki.dwFlags = KEYEVENTF_UNICODE;
        SendInput(1, &input, sizeof(INPUT));
        input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
        SendInput(1, &input, sizeof(INPUT));
        SimulateKeyPress(VK_END,true);
    }
}
void SendUnicodeText(const string& utf8Text) {
    wstring wideText = UTF8ToWide(utf8Text);
    SendUnicodeTextW(wideText);
}

//计算偏移坐标
Coord calculateOffsetCoord(int x, int y, int angle, double distance) {
    double radians = angle * 3.14159265358979323846 / 180.0;
    double dx = distance * sin(radians);
    double dy = distance * cos(radians);
    Coord result;
    result.x = static_cast<int>(round(x + dx));
    result.y = static_cast<int>(round(y - dy));
    return result;
}

//执行命令并读取命令输出
bool readCommandOutput(const string& command) {
    string message;
    int code;
    FILE* pipe = _popen((command + " 2>&1").c_str(), "r");
    if (!pipe) {
        message="错误：无法执行命令";
    }
    array<char, 128> buffer;
    string result;
    while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
        message=buffer.data();
    }
    code = _pclose(pipe);
    cout<<"[INFO]控制台响应信息："<<message <<"\n"<<"[INFO]控制台响应代码："<<code<<"\n\n";
    if(code!=0){
        cout<<"[ERROR]控制台响应代码错误\n\n";
        return false;
    }
    return true;
}

//提取字符之间内容
string extractBetweenChars(const string& str, char startChar, char endChar) {
    size_t startPos = str.find(startChar);
    if (startPos == string::npos) {
        return "";
    }
    
    size_t endPos;
    if (startChar == endChar) {
        endPos = str.find(endChar, startPos + 1);
    } else {
        endPos = str.find(endChar, startPos + 1);
    }
    
    if (endPos == string::npos) {
        return "";
    }
    
    return str.substr(startPos + 1, endPos - startPos - 1);
}

//提取字符之后内容
string extractAfterChar(const string& str, char ch) {
    size_t pos = str.find(ch);
    if (pos == string::npos) {
        return "";
    }
    return str.substr(pos + 1);
}

//获取指定坐标的十六进制颜色码
string GetPixelColorHex(int x, int y) {
    HDC hdcScreen = GetDC(nullptr);
    if (!hdcScreen) {
        return "#ERROR";
    }
    COLORREF color = GetPixel(hdcScreen, x, y);
    ReleaseDC(nullptr, hdcScreen);
    if (color == CLR_INVALID) {
        return "#INVALID";
    }
    BYTE red = GetRValue(color);
    BYTE green = GetGValue(color);
    BYTE blue = GetBValue(color);
    stringstream ss;
    ss << "#" 
       << hex << uppercase << setfill('0')
       << setw(2) << static_cast<int>(red)
       << setw(2) << static_cast<int>(green)
       << setw(2) << static_cast<int>(blue);
    return ss.str();
}

//读取最近一条剪贴板内容
Data GetClipboardText() {
    Data result = { false, "" };
    if (!OpenClipboard(nullptr)) {
        result.message = "无法打开剪贴板";
        return result;
    }
    HANDLE hData = nullptr;
    hData = GetClipboardData(CF_UNICODETEXT);
    if (hData != nullptr) {
        wchar_t* pszWText = static_cast<wchar_t*>(GlobalLock(hData));
        if (pszWText != nullptr) {
            int bufSize = WideCharToMultiByte(CP_UTF8, 0, pszWText, -1, nullptr, 0, nullptr, nullptr);
            string text(bufSize, 0);
            WideCharToMultiByte(CP_UTF8, 0, pszWText, -1, &text[0], bufSize, nullptr, nullptr);
            text.pop_back();
            result.success = true;
            result.message = text;
            GlobalUnlock(hData);
        } else {
            result.message = "无法锁定Unicode文本数据";
        }
    } 
    else {
        hData = GetClipboardData(CF_TEXT);
        if (hData != nullptr) {
            char* pszText = static_cast<char*>(GlobalLock(hData));
            if (pszText != nullptr) {
                result.success = true;
                result.message = string(pszText);
                GlobalUnlock(hData);
            } else {
                result.message = "无法锁定ANSI文本数据";
            }
        } else {
            result.message = "剪贴板内容非文本格式";
        }
    }
    CloseClipboard();
    return result;
}

//判断字符串是否包含一个另字符串
bool contains(const string& str, const string& substring) {
    return str.find(substring) != string::npos;
}

//将文本复制到剪贴板
bool CopyTextToClipboard(const std::wstring& text) {
    if (!OpenClipboard(nullptr)) {
        return false;
    }
    EmptyClipboard();
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t));
    if (!hGlobal) {
        CloseClipboard();
        return false;
    }
    wchar_t* pGlobal = static_cast<wchar_t*>(GlobalLock(hGlobal));
    if (!pGlobal) {
        GlobalFree(hGlobal);
        CloseClipboard();
        return false;
    }
    wcscpy(pGlobal,text.c_str());
    GlobalUnlock(hGlobal);
    SetClipboardData(CF_UNICODETEXT, hGlobal);
    CloseClipboard();
    return true;
}

int main(){
    system("chcp 65001");   //防止控制台乱码
    cout<<"\n自动PCQQ机器人V1.0\n小满工作室制作 侵权必究\n© 2026 小满工作室. All rights reserved.\n";
    cout<<"------------------\n\n";
    cout<<"[INFO]正在识别DPI缩放比例...\n\n";
    dpi=GetDPIScale();
    cout<<"您的DPI："<<fixed<<setprecision(2)<<dpi<<"("<<fixed<<setprecision(0)<<dpi*100<<"%)\n\n";

    cout<<"请使用其他设备向此设备发送一条纯文本消息并按任意键继续\n";
    system("pause");
    cout<<"\n";

    cout<<"请将鼠标放在这条消息的左下角空白部分\n\
    ┏-------------------┓\n\
    |     a message     |\n\
    ┗-↑-----------------┛\n\
    这个位置\n\n";
    cout<<"[INFO]10s后将记录鼠标位置\n";
    for(int i=10;i>=1;i--){
        cout<<"[INFO]倒计时："<<i<<"\n";
        Sleep(1000);
    }
    cout<<"\n";
    Coord messageCoord=GetCurrentMouseCoord();
    cout<<"[INFO]鼠标位置已记录\n\n";

    cout<<"[INFO]请不要移动页面 3s后将记录位置颜色\n";
    for(int i=3;i>=1;i--){
        cout<<"[INFO]倒计时："<<i<<"\n";
        Sleep(1000);
    }
    cout<<"\n";
    string messageCoordColor = GetPixelColorHex(messageCoord.x, messageCoord.y);
    cout<<"[INFO]位置颜色已记录\n\n";
    cout<<"请将鼠标放在输入框的任意位置\n\n";
    cout<<"[INFO]5s后将记录鼠标位置\n";
    for(int i=5;i>=1;i--){
        cout<<"[INFO]倒计时："<<i<<"\n";
        Sleep(1000);
    }
    cout<<"\n";
    Coord inputCoord=GetCurrentMouseCoord();
    cout<<"[INFO]鼠标位置已记录\n\n";

    cout<<"[INFO]信息采集成功\n";
    cout<<"请务必不要更改QQ应用的位置与布局 否则请重新运行本程序\n\n";

    int intervalTime;
    cout<<"请输入循环间隔时间（单位：ms 建议1000）：";
    cin>>intervalTime;
    cout<<"\n\n";
    if(cin.fail()){
        cerr<<"[ERROR]输入的不是有效整数\n\n";
        cerr<<"[ERROR]程序错误结束 退出码：3 请参阅官方文档";
        cout<<"\n\n------------------\n";
        cout<<"防止窗口直接退出 请按任意键继续\n";
        system("pause");
        return 3;
    }

    cout<<"请务必保持QQ应用处于最顶层 可将此窗口移至角落 准备好后按任意键正式运行机器人\n";
    system("pause");
    cout<<"\n";

    cout<<"[INFO]进入主函数\n\n";

    int num=0;
    map<string, string> passphraseMap={
        {"hello bot","我在"}
    };
    while(true){
        num++;
        Sleep(intervalTime);
        if(GetPixelColorHex(messageCoord.x, messageCoord.y)==messageCoordColor){
            MoveMouseTo(messageCoord.x,messageCoord.y);
            Sleep(200);
            SimulateMouseClick();
            SimulateMouseClick();
            SimulateMouseClick();
            Sleep(100);
            SimulateHotkey(VK_CONTROL,'C');
            Sleep(80);
            Data cbt = GetClipboardText();
            if(!CopyTextToClipboard(L"顶替")){
                cerr<<"[WARNING]文本复制失败\n\n";
            }
            if(cbt.success==true){
                cout<<"[INFO]"<<"收到消息："<<cbt.message<<"\n";
                string data = cbt.message;
                string result;
                if(data[0]=='/'){
                    cout<<"[INFO]消息首位为\'/\' 该消息为指令消息\n";
                    string passphrase=data.substr(1);
                    cout<<"[INFO]指令内容："<<passphrase<<"\n";
                    cout<<"[INFO]根据指令库自动回复\n\n";
                    if(passphrase=="help"){
                        result="我是由小满工作室开发的QQ机器人，请使用 /passphraseList 指令获取所有指令列表。详细内容请参阅https://xiaomanstudio.pages.dev/product/pcqqbot。";
                    }
                    else if(contains(passphrase,"setPassphrase")){
                        if(contains(passphrase," ") && contains(passphrase,"&") && passphrase.size()>=17){
                            passphraseMap[extractBetweenChars(passphrase,' ','&')]=extractAfterChar(passphrase,'&');
                            result="指令添加/设置成功";
                        }
                        else{
                            result="指令添加/设置失败 输入不合法";
                        }

                    }
                    else if(contains(passphrase,"rmPassphrase")){
                        if(contains(passphrase," ") && passphrase.size()>=14){
                            if(passphraseMap.find(extractAfterChar(passphrase,' '))!=passphraseMap.end()){
                                passphraseMap.erase(extractAfterChar(passphrase,' '));
                                result="指令删除成功";
                            }
                            else{
                                result="指令删除失败 指令不存在";
                            }
                        }
                        else{
                            result="指令删除失败 输入不合法";
                        }
                        
                    }
                    else if(passphrase=="passphraseList"){
                        MoveMouseTo(inputCoord.x,inputCoord.y);
                        Sleep(20);
                        SimulateMouseClick();
                        SendUnicodeText("请稍后...");
                        SimulateKeyPress(VK_RETURN);
                        Sleep(1000);
                        result="当前存在"+to_string((passphraseMap.size()+4))+"个指令▣\n\n◈指令：help 作用：输出Bot说明\n◈指令：setPassphrase 作用：添加/设置指令\n◈指令：rmPassphrase 作用：删除指令\n◈指令：passphraseList 作用：输出指令列表";
                        for(auto i=passphraseMap.begin();i!=passphraseMap.end();i++){
                            result+="\n◈指令："+i->first+" 作用：输出\""+i->second+"\"";
                        }
                    }
                    else{
                        if(passphraseMap.find(passphrase)!=passphraseMap.end()){
                            result=passphraseMap.at(passphrase);
                        }
                        else{
                           result="不存在的指令"; 
                        }
                    }
                    MoveMouseTo(inputCoord.x,inputCoord.y);
                    Sleep(20);
                    SimulateMouseClick();
                    SendUnicodeText(result);
                    SimulateKeyPress(VK_RETURN);
                }
                else{
                    cout<<"[INFO]"<<"消息首位非\'/\' 该消息非指令消息 跳过"<<"\n\n";
                }
                
            }
            else{
                cerr<<"[ERROR]"<<cbt.message<<"\n\n";
            }
        }
    }

    cout<<"------------------";

    cout<<"\n\n防止窗口直接退出 请按任意键继续\n";
    system("pause");   //防止直接退出
    return 0;
}