#include "pch.h" // Precompiled header
#include <windows.h>
#include <commctrl.h>
#include <iostream>
#include <tchar.h>
#include <shellapi.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <comdef.h>
#include <sstream>
#include <cmath> // For pow() in volume conversion

// Function prototypes
DWORD WINAPI OpenGUI(LPVOID lpParam);
void ToggleWindow();
void SetMicrophoneGain(float gainLevel);

// Global variables
HWND hWnd;
HINSTANCE hInstance;
HWND hGainTrackbar;
HWND hDbInput;
BOOL isWindowVisible = TRUE;
float gainLevel = 0.0f; // Default gain in dB

// Function to set microphone gain
void SetMicrophoneGain(float gainDb) {
    CoInitialize(NULL);

    IMMDeviceEnumerator* pEnumerator = NULL;
    CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);

    IMMDevice* pDevice = NULL;
    pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);

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

    // Convert dB gain to a linear scale (SetMasterVolumeLevelScalar expects values from 0.0 to 1.0)
    float volumeScalar = pow(10.0f, gainDb / 20.0f);
    volumeScalar = min(max(volumeScalar, 0.0f), 1.0f); // Clamping between 0 and 1

    HRESULT hr = pVolume->SetMasterVolumeLevelScalar(volumeScalar, NULL);
    if (FAILED(hr)) {
        std::cerr << "Error setting volume level: " << std::hex << hr << std::endl;
    }
    else {
        std::cout << "Microphone gain set to: " << gainDb << " dB" << std::endl;
    }

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

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

// 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);
        RECT rect;
        GetClientRect(hwnd, &rect);

        HBRUSH hBrush = CreateSolidBrush(RGB(30, 30, 30));
        FillRect(hdc, &rect, hBrush);
        DeleteObject(hBrush);

        SetBkMode(hdc, TRANSPARENT);
        SetTextColor(hdc, RGB(240, 240, 240));

        HFONT hFont = CreateFont(24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
            DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            VARIABLE_PITCH, _T("Segoe UI"));
        SelectObject(hdc, hFont);
        TextOut(hdc, 10, 10, _T("Jakacord"), 9);
        DeleteObject(hFont);

        TCHAR gainText[50];
        _stprintf_s(gainText, _T("Gain Level: %.2f dB"), gainLevel);
        TextOut(hdc, 10, 80, gainText, _tcslen(gainText));

        EndPaint(hwnd, &ps);
        break;
    }
    case WM_HSCROLL:
        if ((HWND)lParam == hGainTrackbar) {
            gainLevel = static_cast<float>(SendMessage(hGainTrackbar, TBM_GETPOS, 0, 0)) / 10.0f;
            InvalidateRect(hwnd, NULL, TRUE);
            SetMicrophoneGain(gainLevel);
        }
        break;
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK) { // OK button clicked
            TCHAR dbText[50];
            GetWindowText(hDbInput, dbText, 50);

            std::wstringstream wss(dbText);
            float inputGainDb;
            if (wss >> inputGainDb) {
                gainLevel = inputGainDb;
                SetMicrophoneGain(gainLevel);
                std::wcout << L"Setting Gain to: " << gainLevel << L" dB" << std::endl;
                InvalidateRect(hwnd, NULL, TRUE);
            }
            else {
                MessageBox(hwnd, _T("Please enter a valid number."), _T("Input Error"), MB_OK | MB_ICONERROR);
            }
        }
        break;
    case WM_HOTKEY:
        if (wParam == 1) { // F5 hotkey
            ToggleWindow();
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

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

    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = _T("Jaka");
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);

    hWnd = CreateWindowEx(
        WS_EX_TOOLWINDOW, _T("Jaka"), _T("Jakacord"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 450, 300,
        NULL, NULL, hInstance, NULL);

    if (!hWnd) return 1;

    RegisterHotKey(hWnd, 1, 0, VK_F5);

    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(-960, 1500)); // -96.0 to 150.0 dB (scaled by 10)
    SendMessage(hGainTrackbar, TBM_SETPOS, TRUE, static_cast<int>(gainLevel * 10));

    hDbInput = CreateWindowEx(0, _T("EDIT"), _T("0"),
        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
        50, 100, 100, 25, hWnd, NULL, hInstance, NULL);

    CreateWindowEx(0, _T("BUTTON"), _T("Set dB"),
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        160, 100, 75, 25, hWnd, (HMENU)IDOK, hInstance, NULL);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    UnregisterHotKey(hWnd, 1);
    return 0;
}

// Entry point of the DLL
extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        AllocConsole();
        freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
        std::cout << "Jakacord (uncapped audio)" << std::endl;
        CreateThread(NULL, 0, OpenGUI, NULL, 0, NULL);
    }
    else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
        FreeConsole();
    }
    return TRUE;
}






remove the manually add db and keep the slider and make this uncapped also add a bitrate slide too