#include "Draw.h"
#include <algorithm>
#include <chrono>
#include <sstream>
#include <iomanip>
#include "../../Backend/Config/Config.h"
#include "../../Backend/Misc/Fonts/FontManager.h"
#include "../Renderer/Renderer.h"
#include <psapi.h>

CConfig* cfg = CConfig::get();

static std::time_t GetSystemTimeRaw()
{
    auto now = std::chrono::system_clock::now();
    return std::chrono::system_clock::to_time_t(now);
}

static std::tm GetSystemTimeLocal()
{
    std::time_t now = GetSystemTimeRaw();
    std::tm localTime;
    localtime_s(&localTime, &now);
    return localTime;
}

static std::string GetSystemTimeString(const char* format)
{
    std::tm localTime = GetSystemTimeLocal();
    std::stringstream ss;
    ss << std::put_time(&localTime, format);
    return ss.str();
}

static void Time() {
    if (!cfg->b["time"])
        return;

    // 时间格式: 0-3 标准(前导零), 4-7 短格式(所有两位数字去前导零)
    static const char* baseFormats[] = { "%H:%M:%S", "%H:%M", "%I:%M:%S %p", "%I:%M %p" };
    int fmtIdx = cfg->i.count("time_format") ? std::clamp(cfg->i["time_format"], 0, 7) : 0;
    bool shortFormat = (fmtIdx >= 4);
    std::string time = GetSystemTimeString(baseFormats[shortFormat ? (fmtIdx - 4) : fmtIdx]);

    // 短格式：去除所有两位数字的前导零  "01:02:03" → "1:2:3"
    if (shortFormat)
    {
        std::string out;
        for (size_t i = 0; i < time.size(); i++)
        {
            if (time[i] == '0' && i + 1 < time.size()
                && time[i + 1] >= '0' && time[i + 1] <= '9'
                && (i == 0 || time[i - 1] < '0' || time[i - 1] > '9'))
            {
                continue; // skip leading zero
            }
            out += time[i];
        }
        time = out;
    }

    // 分离主时间部分与 AM/PM 后缀
    std::string timeMain = time;
    std::string timeSuffix;
    const char* ampmMarkers[] = { " AM", " PM" };
    for (int mi = 0; mi < 2; mi++)
    {
        size_t pos = time.rfind(ampmMarkers[mi]);
        if (pos != std::string::npos)
        {
            timeMain = time.substr(0, pos);
            timeSuffix = ampmMarkers[mi];
            break;
        }
    }

    auto& fm = FontManager::GetInstance();

    // 注册主字体
    int fontSize = cfg->i["time_text_size"];
    if (fontSize <= 0) fontSize = 45;

    static int lastFontSize = 0;
    if (lastFontSize != fontSize) {
        if (lastFontSize == 0)
            fm.RegisterFont("TimeFont", "C:\\Windows\\Fonts\\Verdana.ttf", fontSize);
        else
            fm.SetFontBaseSize("TimeFont", fontSize);
        lastFontSize = fontSize;
    }
    fm.EnsureText("TimeFont", timeMain.c_str());
    RLFont font = fm.GetFont("TimeFont");
    float charSpacing = (float)cfg->i["time_text_character_spacing"];

    // 注册 AM/PM 小字体（主字体 ~55% 大小）
    RLFont smallFont = { 0 };
    int suffixFontSize = 0;
    float suffixOffsetX = 0.f;
    if (!timeSuffix.empty())
    {
        suffixFontSize = std::max(8, (int)(fontSize * 0.55f));
        static int lastSuffixSize = 0;
        if (lastSuffixSize != suffixFontSize) {
            if (lastSuffixSize == 0)
                fm.RegisterFont("TimeFontSmall", "C:\\Windows\\Fonts\\Verdana.ttf", suffixFontSize);
            else
                fm.SetFontBaseSize("TimeFontSmall", suffixFontSize);
            lastSuffixSize = suffixFontSize;
        }
        fm.EnsureText("TimeFontSmall", timeSuffix.c_str());
        smallFont = fm.GetFont("TimeFontSmall");
        // 后缀 X 偏移 = 主时间文本宽度 + 字符间距
        RLVector2 mainSize = fm.MeasureText("TimeFont", timeMain.c_str(), fontSize);
        suffixOffsetX = mainSize.x + charSpacing;
    }

    const int* color = cfg->c["time_text_Color"];
    RLColor textColor = {
        static_cast<unsigned char>(color[0]),
        static_cast<unsigned char>(color[1]),
        static_cast<unsigned char>(color[2]),
        static_cast<unsigned char>(color[3])
    };

    float xPos = cfg->f["time_x_pos"];
    float yPos = cfg->f["time_y_pos"];
    // AM/PM 垂直偏下偏移靠左
    float suffixOffsetY = timeSuffix.empty() ? 0.f : ((float)fontSize - (float)suffixFontSize) * 0.65f;

    const int* colorborder = cfg->c["text_border_Color"];
    RLColor borderCol = { 
        static_cast<unsigned char>(colorborder[0]),
        static_cast<unsigned char>(colorborder[1]),
        static_cast<unsigned char>(colorborder[2]),
        static_cast<unsigned char>(colorborder[3])
    };
    if (cfg->b["text_border"]) {
        for (int dy = -1; dy <= 1; ++dy) {
            for (int dx = -1; dx <= 1; ++dx) {
                if (dx == 0 && dy == 0) continue;
                RLDrawTextEx(font, timeMain.c_str(), RLVector2{ xPos + (float)dx, yPos + (float)dy }, (float)fontSize, charSpacing, borderCol);

            }
        }
    }
    
    RLDrawTextEx(font, timeMain.c_str(), RLVector2{ xPos, yPos }, (float)fontSize, charSpacing, textColor);
}

static std::string GetForegroundProcessName() {
    HWND fg = GetForegroundWindow();
    if (!fg) return "";
    DWORD pid = 0;
    GetWindowThreadProcessId(fg, &pid);
    if (pid == 0) return "";
    HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    if (!hProc) return "";
    char exeName[MAX_PATH] = "";
    DWORD size = MAX_PATH;
    if (!QueryFullProcessImageNameA(hProc, 0, exeName, &size)) {
        CloseHandle(hProc);
        return "";
    }
    CloseHandle(hProc);
    const char* base = strrchr(exeName, '\\');
    return base ? (base + 1) : exeName;
}

static bool IsWindowWhitelisted() {
    std::string whitelist(cfg->s["keyboard_whitelist"]);
    if (whitelist.empty()) return false;

    std::string fgName = GetForegroundProcessName();
    if (fgName.empty()) return false;

    // Case-insensitive exact match against whitelist entries
    size_t pos = 0;
    while (pos < whitelist.size()) {
        size_t end = whitelist.find(';', pos);
        if (end == std::string::npos) end = whitelist.size();
        std::string entry = whitelist.substr(pos, end - pos);
        if (!entry.empty() && _stricmp(entry.c_str(), fgName.c_str()) == 0)
            return true;
        pos = end + 1;
    }
    return false;
}

static void KeyboardControl() {
    if (!cfg->b["keyboard_control"])
        return;

    // Skip control if active window is in whitelist
    if (IsWindowWhitelisted())
        return;

    // Throttle: only attempt toggle every 250ms to prevent frame-rate flicker
    // when the game also fights for lock-key state
    static ULONGLONG lastAttempt = 0;
    ULONGLONG now = GetTickCount64();
    if (now - lastAttempt < 250)
        return;
    lastAttempt = now;

    // Caps Lock control
    {
        int mode = cfg->i["Caps_control"];
        if (mode != 0) {
            bool capsOn = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
            bool wantOn = (mode == 1); // 1=常开(Always On), 2=常关(Always Off)
            if (capsOn != wantOn) {
                // keybd_event is NOT subject to UIPI (unlike SendInput), so it works with elevated fullscreen games
                keybd_event(VK_CAPITAL, 0x3A, 0, 0);
                keybd_event(VK_CAPITAL, 0x3A, KEYEVENTF_KEYUP, 0);
            }
        }
    }

    // Num Lock control
    {
        int mode = cfg->i["Num_control"];
        if (mode != 0) {
            bool numOn = (GetKeyState(VK_NUMLOCK) & 0x0001) != 0;
            bool wantOn = (mode == 1); // 1=常开(Always On), 2=常关(Always Off)
            if (numOn != wantOn) {
                // keybd_event is NOT subject to UIPI (unlike SendInput), so it works with elevated fullscreen games
                keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
                keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
            }
        }
    }
}

namespace Render {

void DrawOverlay() {
    KeyboardControl();
    Time();
}

} // namespace Render