#include "../Globalincludes.h"
#include "../../Overlay/Overlay.h"
#include "../Config/Config.h"
#include "../Console/Console.h"

static HANDLE g_hSingleInstanceMutex = NULL;

bool IsRunningAsAdmin()
{
    BOOL bIsAdmin = FALSE;
    PSID pAdminGroup = 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, &pAdminGroup))
    {
        CheckTokenMembership(NULL, pAdminGroup, &bIsAdmin);
        FreeSid(pAdminGroup);
    }

    return (bIsAdmin != FALSE);
}

void ReleaseSingleInstanceMutex()
{
    if (g_hSingleInstanceMutex)
    {
        ReleaseMutex(g_hSingleInstanceMutex);
        CloseHandle(g_hSingleInstanceMutex);
        g_hSingleInstanceMutex = NULL;
    }
}

int main()
{
    bool bUnelevated = (wcsstr(GetCommandLineW(), L"--unelevated") != NULL);
    bool bConhost    = (wcsstr(GetCommandLineW(), L"--conhost")    != NULL);

    // Restart via conhost.exe for classic console
    if (!bConhost && !bUnelevated) {
        wchar_t buf[2048];
        swprintf_s(buf, L"conhost.exe %s --conhost", GetCommandLineW());
        STARTUPINFOW si = { sizeof(si) };
        PROCESS_INFORMATION pi = {};
        if (CreateProcessW(NULL, buf, NULL, NULL, FALSE, 0,
            NULL, NULL, &si, &pi)) {
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            return 0;
        }
    }

    // One-time console setup: title, icon, guard thread
    Console::Get()->Initialize();

    // Hide console immediately (avoids flash). Menu::Initialize() shows it if configured.
    Console::Get()->SetVisible(false);

    // When de-elevated via schtasks, CWD defaults to system32.
    // Fix it to the exe's directory so configs/fonts load correctly.
    if (bUnelevated) {
        wchar_t exePath[MAX_PATH];
        GetModuleFileNameW(NULL, exePath, MAX_PATH);
        WCHAR* p = wcsrchr(exePath, L'\\');
        if (p) { *p = L'\0'; SetCurrentDirectoryW(exePath); }
    }

    g_hSingleInstanceMutex = CreateMutexW(NULL, TRUE, L"Rcjy_SingleInstance_Mutex");
    if (g_hSingleInstanceMutex && GetLastError() == ERROR_ALREADY_EXISTS)
    {
        CloseHandle(g_hSingleInstanceMutex);
        g_hSingleInstanceMutex = NULL;

        if (bUnelevated) {
            // Wait for the old instance to release the mutex (max ~3 s)
            for (int i = 0; i < 30; ++i) {
                Sleep(100);
                g_hSingleInstanceMutex = CreateMutexW(NULL, TRUE, L"Rcjy_SingleInstance_Mutex");
                if (g_hSingleInstanceMutex && GetLastError() != ERROR_ALREADY_EXISTS)
                    break;
                if (g_hSingleInstanceMutex) {
                    CloseHandle(g_hSingleInstanceMutex);
                    g_hSingleInstanceMutex = NULL;
                }
            }
            if (!g_hSingleInstanceMutex) {
                MessageBoxW(NULL, L"无法重启程序（旧实例未退出）", L"Rcjy", MB_OK | MB_ICONWARNING);
                return 0;
            }
        } else {
            MessageBoxW(NULL, L"程序已在运行中", L"Rcjy", MB_OK | MB_ICONINFORMATION);
            return 0;
        }
    }

    auto overlay = COverlay::Get();

    if (!overlay->Initialize())
    {
        ReleaseSingleInstanceMutex();
        return 1;
    }

    // Apply console visibility from saved config
    Console::Get()->SetVisible(CConfig::get()->b["show_console"]);

    while (overlay->IsRunning())
    {
        overlay->Render();
    }

    overlay->Shutdown();
    Console::Get()->Shutdown();
    ReleaseSingleInstanceMutex();
    return 0;
}
