#include "pch.h" // Precompiled header
#include <windows.h>
#include <commctrl.h> // Necessary for using common controls like trackbar
#include <iostream>
#include <tchar.h>
#include <shellapi.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <comdef.h>

// Function prototype for GUI and Hotkey handling
DWORD WINAPI OpenGUI(LPVOID lpParam);
void RestartDiscord();
void ToggleWindow();
void SetMicrophoneGain(float gain); // Function to apply microphone gain

// Global variables for the GUI
HWND hWnd;
HINSTANCE hInstance;
HWND hGainTrackbar; // Trackbar handle
BOOL isWindowVisible = TRUE; // Start visible for testing
BOOL buttonHovered = FALSE; // Track if button is hovered
int gainLevel = 50; // Track gain level (initially set to 50)

// Function to draw a filled rounded rectangle
void FillRoundedRect(HDC hdc, RECT rect, int radius) {
    // Create a path
    HRGN roundedRectPath = CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, radius, radius);
    FillRgn(hdc, roundedRectPath, (HBRUSH)(COLOR_WINDOW + 1)); // Fill with the button background color
    DeleteObject(roundedRectPath); // Clean up the region object
}

// Custom Drawing Method for ImGui-like appearance
void PaintWindow(HDC hdc) {
    RECT rect;
    GetClientRect(hWnd, &rect);

    // Fill background
    FillRect(hdc, &rect, (HBRUSH)(COLOR_BTNSHADOW + 1)); // Dark background

    // Set up for text drawing
    SetBkMode(hdc, TRANSPARENT);
    SetTextColor(hdc, RGB(240, 240, 240)); // Light gray text

    // Draw title text
    const TCHAR* titleText = _T("Jakacord");
    TextOut(hdc, 10, 10, titleText, _tcslen(titleText));

    // Draw button-like rectangle
    RECT buttonRect = { 50, 60, 400, 100 }; // Coordinates for Restart Discord button

    // Draw button background based on hover status
    FillRoundedRect(hdc, buttonRect, 15); // Draw the button with rounded corners

    // Draw border for button
    FrameRect(hdc, &buttonRect, (HBRUSH)(COLOR_WINDOWFRAME + 1));

    // Draw text in the button
    DrawText(hdc, _T("Restart Discord"), -1, &buttonRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    // Draw gain label
    TCHAR gainText[50];
    _stprintf_s(gainText, _T("Gain Level: %d"), gainLevel);
    TextOut(hdc, 10, 120, gainText, _tcslen(gainText));
}

// Window Procedure
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        PaintWindow(hdc);
        EndPaint(hwnd, &ps);
        break;
    }
    case WM_LBUTTONDOWN: {
        // Check if the mouse is inside the button area
        POINT pt = { LOWORD(lParam), HIWORD(lParam) };
        RECT buttonRect = { 50, 60, 400, 100 };

        // Handle button click
        if (PtInRect(&buttonRect, pt)) {
            RestartDiscord();
        }
        break;
    }
    case WM_MOUSEMOVE: {
        // Check if the mouse is over the button
        POINT pt = { LOWORD(lParam), HIWORD(lParam) };
        RECT buttonRect = { 50, 60, 400, 100 };

        buttonHovered = PtInRect(&buttonRect, pt);
        InvalidateRect(hwnd, NULL, TRUE); // Redraw to reflect hover state
        break;
    }
    case WM_HSCROLL: { // Handle trackbar updates
        if ((HWND)lParam == hGainTrackbar) {
            gainLevel = SendMessage(hGainTrackbar, TBM_GETPOS, 0, 0);
            InvalidateRect(hwnd, NULL, TRUE); // Redraw to show updated gain

            // Set microphone gain based on slider position
            SetMicrophoneGain(gainLevel / 100.0f); // Normalize gain to 0.0 to 1.0 range
        }
        break;
    }
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_HOTKEY: // Hotkey processing
        if (wParam == 1) { // F5 hotkey
            ToggleWindow();
        }
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// Function to toggle GUI visibility
void ToggleWindow() {
    isWindowVisible = !isWindowVisible;
    ShowWindow(hWnd, isWindowVisible ? SW_SHOW : SW_HIDE);
}

// Function to create GUI
DWORD WINAPI OpenGUI(LPVOID lpParam) {
    // Get the current instance
    hInstance = GetModuleHandle(NULL);

    // Initialize common controls
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_COOL_CLASSES; // Initialize we will use other classes, including trackbars
    InitCommonControlsEx(&icex);

    // Register window class
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = _T("Jaka"); // Use consistent class name
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    if (!RegisterClass(&wc)) {
        MessageBox(NULL, _T("Failed to register window class!"), _T("Error"), MB_ICONERROR);
        return 1;
    }

    // Create the window
    hWnd = CreateWindowEx(
        WS_EX_TOOLWINDOW, // Tool window style
        _T("Jaka"), // Consistent class name
        _T("Jakacord"), // Window title
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, // Start visible for testing
        CW_USEDEFAULT, CW_USEDEFAULT, 450, 250,
        NULL, NULL, hInstance, NULL);

    if (!hWnd) {
        DWORD error = GetLastError();
        TCHAR errorMsg[256];
        _stprintf_s(errorMsg, _T("Failed to create window! Error code: %lu"), error);
        MessageBox(NULL, errorMsg, _T("Error"), MB_ICONERROR);
        return 1;
    }

    // Create the hotkey (F5)
    if (!RegisterHotKey(hWnd, 1, 0, VK_F5)) {
        MessageBox(NULL, _T("Failed to register hotkey!"), _T("Error"), MB_ICONERROR);
        return 1;
    }

    // Create a trackbar for gain control
    hGainTrackbar = CreateWindowEx(
        0,
        TRACKBAR_CLASS,
        NULL,
        WS_CHILD | WS_VISIBLE | TBS_BOTH | TBS_NOTICKS,
        50, 150, 400, 30,
        hWnd, NULL, hInstance, NULL);

    SendMessage(hGainTrackbar, TBM_SETRANGE, TRUE, MAKELONG(0, 100)); // Set range (0 to 100)
    SendMessage(hGainTrackbar, TBM_SETPOS, TRUE, gainLevel); // Set initial position

    UpdateWindow(hWnd); // Update the window to reflect changes

    // Message loop to keep the GUI responsive
    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Unregister the hotkey before exiting
    UnregisterHotKey(hWnd, 1);
    return 0;
}

// Function to restart Discord
void RestartDiscord() {
    system("taskkill /F /IM discord.exe");
    Sleep(3000); // Wait for a moment to ensure Discord has closed

    char discordPath[MAX_PATH];
    if (GetEnvironmentVariableA("LOCALAPPDATA", discordPath, MAX_PATH)) {
        strcat_s(discordPath, "\\Discord\\Update.exe");
        ShellExecuteA(0, "open", discordPath, "--processStart Discord.exe", NULL, SW_SHOW);
        MessageBox(NULL, _T("Discord has been restarted."), _T("Notification"), MB_OK | MB_ICONINFORMATION);
    }
    else {
        MessageBox(NULL, _T("Failed to get Discord path."), _T("Error"), MB_ICONERROR);
    }
}

// Function to set microphone gain using the MMDevice API
void SetMicrophoneGain(float gain) {
    // Initialize COM library
    CoInitialize(NULL);

    // Create the device enumerator
    IMMDeviceEnumerator* pEnumerator = NULL;
    CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);

    // Get the default audio device (microphone)
    IMMDevice* pDevice = NULL;
    pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);

    // Activate the volume interface
    IAudioEndpointVolume* pVolume = NULL;
    pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pVolume);

    // Set the volume level (gain)
    pVolume->SetMasterVolumeLevelScalar(gain, NULL); // Gain is between 0.0 and 1.0

    // Clean up
    pVolume->Release();
    pDevice->Release();
    pEnumerator->Release();

    // Uninitialize COM
    CoUninitialize();
}

// Entry point of the DLL - manages loading and unloading
extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        AllocConsole(); // Optional: allocate a console for debug output
        {
            FILE* fp;
            freopen_s(&fp, "CONOUT$", "w", stdout);
            std::cout << "Welcome to Jakasauce! You are now 5dB over the limit.(credits to arkham)" << std::endl;
        }

        // Start the GUI thread
        CreateThread(NULL, 0, OpenGUI, NULL, 0, NULL);
        break;

    case DLL_PROCESS_DETACH:
        FreeConsole();
        break;
    }
    return TRUE;
}





put the gain limit to 1000db so it can be loud