#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <tlhelp32.h>
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>

namespace fs = std::filesystem;

// Kiểm tra quyền Administrator
bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID adminGroup = NULL;
    SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
    if (AllocateAndInitializeSid(&ntAuthority, 2,
                                  SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_ADMINS,
                                  0, 0, 0, 0, 0, 0,
                                  &adminGroup)) {
        CheckTokenMembership(NULL, adminGroup, &isAdmin);
        FreeSid(adminGroup);
    }
    return isAdmin == TRUE;
}

// Tự nâng quyền Administrator (UAC self-elevation)
bool RelaunchAsAdmin() {
    wchar_t szPath[MAX_PATH];
    if (GetModuleFileNameW(NULL, szPath, MAX_PATH)) {
        SHELLEXECUTEINFOW sei = { sizeof(sei) };
        sei.lpVerb = L"runas";
        sei.lpFile = szPath;
        sei.hwnd = NULL;
        sei.nShow = SW_NORMAL;
        if (ShellExecuteExW(&sei)) {
            return true;
        }
    }
    return false;
}

// Tìm PID của tiến trình theo tên file exe (không phân biệt hoa thường)
uint32_t FindProcessId(const std::wstring& processName) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32W entry{};
    entry.dwSize = sizeof(entry);

    uint32_t foundPid = 0;
    if (Process32FirstW(snapshot, &entry)) {
        do {
            if (_wcsicmp(entry.szExeFile, processName.c_str()) == 0) {
                foundPid = entry.th32ProcessID;
                break;
            }
        } while (Process32NextW(snapshot, &entry));
    }
    CloseHandle(snapshot);
    return foundPid;
}

// Tự động tìm PID của client game POE2 qua danh sách tên file exe phổ biến
uint32_t FindPoeProcessId(std::wstring* outName = nullptr) {
    const std::wstring candidateNames[] = {
        L"PathOfExile.exe",
        L"PathOfExileSteam.exe",
        L"PathOfExile_x64.exe",
        L"PathOfExile_x64Steam.exe",
        L"PathOfExile2.exe"
    };
    for (const auto& name : candidateNames) {
        uint32_t pid = FindProcessId(name);
        if (pid != 0) {
            if (outName) *outName = name;
            return pid;
        }
    }
    return 0;
}

// Kiểm tra xem client game Path of Exile 2 có đang chạy hay không (kiểm tra toàn diện cả HWND lẫn Process ID)
bool IsPoe2Running() {
    // 1. Kiểm tra HWND theo window class và window title
    if (FindWindowW(L"POEWindowClass", nullptr)) return true;
    if (FindWindowW(L"POEC2_MainWindow", nullptr)) return true;
    if (FindWindowW(nullptr, L"Path of Exile 2")) return true;
    if (FindWindowW(nullptr, L"Path of Exile")) return true;

    // 2. Kiểm tra Process ID qua CreateToolhelp32Snapshot
    if (FindPoeProcessId() != 0) {
        return true;
    }

    return false;
}

// Tự động dò tìm đường dẫn PathOfExile.exe từ các thư mục mặc định và Windows Registry
fs::path FindPoe2ClientExe() {
    std::vector<fs::path> candidates = {
        L"C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile 2\\PathOfExile.exe",
        L"C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile 2\\PathOfExile_x64.exe",
        L"C:\\Program Files\\Grinding Gear Games\\Path of Exile 2\\PathOfExile.exe",
        L"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile 2\\PathOfExileSteam.exe",
        L"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile 2\\PathOfExile.exe",
        L"D:\\SteamLibrary\\steamapps\\common\\Path of Exile 2\\PathOfExileSteam.exe",
        L"D:\\SteamLibrary\\steamapps\\common\\Path of Exile 2\\PathOfExile.exe",
        L"D:\\Games\\Path of Exile 2\\PathOfExile.exe",
        L"E:\\SteamLibrary\\steamapps\\common\\Path of Exile 2\\PathOfExileSteam.exe",
        L"E:\\SteamLibrary\\steamapps\\common\\Path of Exile 2\\PathOfExile.exe",
        L"E:\\Games\\Path of Exile 2\\PathOfExile.exe"
    };
    for (const auto& p : candidates) {
        if (fs::exists(p) && fs::file_size(p) > 1000000) return p;
    }

    // Kiểm tra Windows Registry
    HKEY hKey = nullptr;
    const wchar_t* subKeys[] = {
        L"SOFTWARE\\Grinding Gear Games\\Path of Exile 2",
        L"SOFTWARE\\WOW6432Node\\Grinding Gear Games\\Path of Exile 2"
    };
    for (auto root : { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }) {
        for (auto subKey : subKeys) {
            if (RegOpenKeyExW(root, subKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
                wchar_t installDir[MAX_PATH];
                DWORD bufSize = sizeof(installDir);
                if (RegQueryValueExW(hKey, L"InstallLocation", nullptr, nullptr, (LPBYTE)installDir, &bufSize) == ERROR_SUCCESS) {
                    fs::path p = fs::path(installDir) / L"PathOfExile.exe";
                    RegCloseKey(hKey);
                    if (fs::exists(p)) return p;
                } else {
                    RegCloseKey(hKey);
                }
            }
        }
    }
    return {};
}

int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
    // 1. Kiểm tra và nâng quyền Administrator nếu chưa có
    if (!IsRunAsAdmin()) {
        std::wcout << L"[AutoPOE2 Launcher] Yeu cau quyen Administrator de can thiep bo nho game...\n";
        if (RelaunchAsAdmin()) {
            return 0; // Thoát tiến trình không quyền, nhường quyền cho tiến trình đã nâng cấp
        } else {
            std::wcerr << L"[AutoPOE2 Error] Nguoi dung da tu choi quyen Administrator!\n";
            return 1;
        }
    }

    std::cout << "========================================================\n";
    std::cout << "   AutoPOE2 - HE THONG TU HANH TOAN DIEN (1-CLICK RUN)  \n";
    std::cout << "========================================================\n";

    // 2. Xác định thư mục gốc của dự án
    wchar_t exePathW[MAX_PATH];
    GetModuleFileNameW(NULL, exePathW, MAX_PATH);
    fs::path rootDir = fs::path(exePathW).parent_path();

    std::cout << "[AutoPOE2] Thu muc lam viec: " << rootDir.string() << "\n";

    // 3. Tìm kiếm file thực thi C++ Core Engine
    std::vector<fs::path> coreCandidates = {
        rootDir / "bin" / "Release" / "AutoPOE2_Core.exe",
        rootDir / "bin" / "AutoPOE2_Core.exe",
        rootDir / "build" / "bin" / "Release" / "AutoPOE2_Core.exe"
    };

    fs::path coreExe;
    for (const auto& p : coreCandidates) {
        if (fs::exists(p)) {
            coreExe = p;
            break;
        }
    }

    if (coreExe.empty()) {
        std::cerr << "[AutoPOE2 Error] Khong tim thay AutoPOE2_Core.exe! Vui long bien dich C++ truoc.\n";
        system("pause");
        return 1;
    }

    std::cout << "[AutoPOE2] Phat hien C++ Core Engine: " << coreExe.string() << "\n";

    // 4. Tìm kiếm Python Executable (.venv hoặc Python hệ thống)
    std::vector<fs::path> pythonCandidates = {
        rootDir / ".venv" / "Scripts" / "python.exe",
        rootDir.parent_path() / ".venv" / "Scripts" / "python.exe"
    };

    fs::path pythonExe = "python.exe"; // Fallback hệ thống
    for (const auto& p : pythonCandidates) {
        if (fs::exists(p)) {
            pythonExe = p;
            break;
        }
    }

    std::cout << "[AutoPOE2] Su dung Python: " << pythonExe.string() << "\n";

    // 4.5. Tự động kiểm tra và khởi chạy Path of Exile 2 Client nếu chưa chạy
    if (!IsPoe2Running()) {
        fs::path poeExe = FindPoe2ClientExe();
        if (!poeExe.empty()) {
            std::cout << "[AutoPOE2 Launcher] >> PHAT HIEN GAME CHUA CHAY! Dang tu dong mo: " << poeExe.string() << " <<\n";
            std::wstring gameDir = poeExe.parent_path().wstring();

            STARTUPINFOW si = { sizeof(si) };
            PROCESS_INFORMATION pi = { 0 };
            BOOL started = CreateProcessW(poeExe.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, gameDir.c_str(), &si, &pi);
            if (started) {
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
            } else {
                // Fallback sang ShellExecuteW open và runas
                HINSTANCE hInst = ShellExecuteW(NULL, L"open", poeExe.c_str(), NULL, gameDir.c_str(), SW_SHOWNORMAL);
                if (reinterpret_cast<INT_PTR>(hInst) <= 32) {
                    ShellExecuteW(NULL, L"runas", poeExe.c_str(), NULL, gameDir.c_str(), SW_SHOWNORMAL);
                }
            }

            std::cout << "[AutoPOE2 Launcher] Dang cho game nap shaders va cua so san sang (toi da 35s)...\n";
            // Chờ cửa sổ xuất hiện và nạp shaders (tối đa 35s, chu kỳ 1s)
            bool gameReady = false;
            for (int w = 1; w <= 35; ++w) {
                Sleep(1000);
                if (IsPoe2Running()) {
                    std::cout << "[AutoPOE2 Launcher] Cua so game da san sang (sau " << w << "s)!\n";
                    Sleep(3000); // Chờ splash screen và ổn định shader cache
                    gameReady = true;
                    break;
                }
                if (w % 5 == 0) {
                    std::cout << "[AutoPOE2 Launcher] Dang cho game khoi dong va nap shaders... (" << w << "/35s)\n";
                }
            }
            if (!gameReady) {
                std::cout << "[AutoPOE2 Launcher Warning] Da cho 35s nhung chua phat hien cua so game. Tiep tuc khoi chay Core o che do Standby an toan...\n";
            }
        } else {
            std::cout << "[AutoPOE2 Launcher Note] Chua phat hien game dang chay. Core Engine se o che do Standby cho nguoi dung bat game.\n";
        }
    } else {
        std::cout << "[AutoPOE2 Launcher] Cua so game Path of Exile 2 dang chay san sang.\n";
    }

    // 5. Khởi chạy C++ Core Engine ở chế độ nền (Background Process)
    // QUY TẮC AN TOÀN TUYỆT ĐỐI:
    // Nếu sau 35s !IsPoe2Running() (game không khởi động được hoặc người dùng hủy):
    // TUYỆT ĐỐI KHÔNG truyền cờ --move cho C++ Core!
    // Chỉ chạy Core ở chế độ giám sát an toàn (không phím chuột):
    // std::string coreCmd = "\"" + coreExe.string() + "\" --autododge --autoflask --autoloot --autocombo --autoquest --autopatrol"; // KHÔNG có --move
    // Nếu game ĐÃ CHẠY (IsPoe2Running() == true): Mới được phép truyền thêm --move.
    std::string coreCmd;
    if (IsPoe2Running()) {
        std::cout << "[AutoPOE2] Game dang chay -> Kich hoat che do Tu Hanh Day Du (bao gom --move). Zoom/Fog: Visual Tool rieng.\n";
        coreCmd = "\"" + coreExe.string() + "\" --autododge --autoflask --autoloot --autocombo --autoquest --autopatrol --move";
    } else {
        std::cout << "[AutoPOE2 Warning] Game chua chay hoac chua san sang! TUYET DOI KHONG truyen co --move de bao ve an toan chuot/phim.\n";
        std::cout << "[AutoPOE2] Khoi chay Core o che do Giam Sat An Toan (Standby). Zoom/Fog: Visual Tool rieng.\n";
        coreCmd = "\"" + coreExe.string() + "\" --autododge --autoflask --autoloot --autocombo --autoquest --autopatrol"; // KHÔNG có --move
    }
    STARTUPINFOA siCore = { sizeof(siCore) };
    PROCESS_INFORMATION piCore = { 0 };
    siCore.dwFlags = STARTF_USESHOWWINDOW;
    siCore.wShowWindow = SW_HIDE; // Chạy ngầm không làm phiền người dùng

    std::cout << "[AutoPOE2] Dang khoi chay C++ Core Engine (120Hz Hot Path)...\n";
    BOOL coreOk = CreateProcessA(
        NULL,
        coreCmd.data(),
        NULL,
        NULL,
        FALSE,
        CREATE_NO_WINDOW,
        NULL,
        rootDir.string().c_str(),
        &siCore,
        &piCore
    );

    if (!coreOk) {
        std::cerr << "[AutoPOE2 Warning] Khong the khoi chay C++ Core ngam! Ma loi: " << GetLastError() << "\n";
    }

    // 6. Khởi chạy Giao diện Tự hành Python Control Center
    fs::path runScript = rootDir / "run_control_center.py";
    std::string pyCmd = "\"" + pythonExe.string() + "\" \"" + runScript.string() + "\"";

    STARTUPINFOA siPy = { sizeof(siPy) };
    PROCESS_INFORMATION piPy = { 0 };

    std::cout << "[AutoPOE2] Dang khoi chay Bang Dieu Hanh Tu Hanh (Autonomous Control Center)...\n";
    BOOL pyOk = CreateProcessA(
        NULL,
        pyCmd.data(),
        NULL,
        NULL,
        FALSE,
        0,
        NULL,
        rootDir.string().c_str(),
        &siPy,
        &piPy
    );

    if (!pyOk) {
        std::cerr << "[AutoPOE2 Error] Khong the khoi chay Python Control Center! Ma loi: " << GetLastError() << "\n";
        if (coreOk) {
            TerminateProcess(piCore.hProcess, 0);
            CloseHandle(piCore.hProcess);
            CloseHandle(piCore.hThread);
        }
        system("pause");
        return 1;
    }

    // 7. Chờ tiến trình Giao diện kết thúc (Người dùng tắt app)
    std::cout << "[AutoPOE2] He thong tu hanh dang chay! Dong cua so giao dien de ket thuc toan bo.\n";
    WaitForSingleObject(piPy.hProcess, INFINITE);

    // 8. Thu hồi và đóng an toàn C++ Core Engine
    std::cout << "[AutoPOE2] Dang dong toan bo tien trinh C++ va don dep he thong...\n";
    if (coreOk) {
        TerminateProcess(piCore.hProcess, 0);
        WaitForSingleObject(piCore.hProcess, 2000);
        CloseHandle(piCore.hProcess);
        CloseHandle(piCore.hThread);
    }

    CloseHandle(piPy.hProcess);
    CloseHandle(piPy.hThread);

    std::cout << "[AutoPOE2] He thong da tat an toan.\n";
    return 0;
}
