#include <windows.h>
#include <commctrl.h>
#include <iostream>
#include <tlhelp32.h>
#include <string>
#include <memory>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>

#pragma comment(lib, "Comctl32.lib")

HANDLE hProcess;
LPVOID voiceEngineAddr;
DWORD discordProcessID;

float gain = 100.0f;  // Default gain (100 dB)
HWND hWnd; // Main window handle
HWND hSlider; // Slider handle
HWND hGainText; // Textbox handle

// Function to find Discord's process ID
DWORD GetDiscordProcessID() {
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot == INVALID_HANDLE_VALUE)
        return 0;

    if (Process32First(hSnapshot, &pe32)) {
        do {
            if (_wcsicmp(pe32.szExeFile, L"Discord.exe") == 0) {
                CloseHandle(hSnapshot);
                return pe32.th32ProcessID;
            }
        } while (Process32Next(hSnapshot, &pe32));
    }
    CloseHandle(hSnapshot);
    return 0;
}

// Function to inject the DLL into the Discord process
void InjectDLL() {
    discordProcessID = GetDiscordProcessID();
    if (discordProcessID == 0) {
        std::cerr << "Discord not found!" << std::endl;
        return;
    }

    // Open the Discord process
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, discordProcessID);
    if (hProcess == NULL) {
        std::cerr << "Failed to open Discord process!" << std::endl;
        return;
    }

    // Get the base address of the voice engine (placeholder)
    voiceEngineAddr = (LPVOID)0x12345678;  // Replace with the correct address
}

// Function to modify gain (this will be called from GUI)
void SetGain(float newGain) {
    gain = newGain;

    // Modify the voice engine's gain value (you need to identify how Discord stores this)
    // This is just an example, you need to properly hook into Discord's memory
    WriteProcessMemory(hProcess, voiceEngineAddr, &gain, sizeof(gain), NULL);
}

// Function to set microphone gain using WASAPI
void SetMicrophoneGain(float gain) {
    // WASAPI range is -96.0 dB to 0.0 dB. We'll need to map the gain to this range.
    // Unfortunately, we cannot set 1000 dB as WASAPI only supports a max of 0.0 dB.
    // You can simulate higher gain by increasing the slider range and normalizing it.

    if (gain > 0.0f) {
        gain = 0.0f;  // Cap the gain to 0.0 dB (the max limit of WASAPI)
    }

    CoInitialize(nullptr);

    IMMDeviceEnumerator* pEnumerator = nullptr;
    IMMDevice* pDevice = nullptr;
    IAudioEndpointVolume* pVolume = nullptr;

    // Get the default audio capture device
    CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
    pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
    pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, (void**)&pVolume);

    // Set the microphone gain (range -96.0 to 0.0 dB, 0.0 being the max gain)
    pVolume->SetMasterVolumeLevel(gain, nullptr);

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

// Function to create a simple window for gain control
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            return 0;

        case WM_COMMAND:
            if (LOWORD(wParam) == 1) {  // Apply button clicked
                int sliderPos = SendMessage(hSlider, TBM_GETPOS, 0, 0);  // Get slider position
                float newGain = (float)sliderPos;  // Convert to gain value
                SetGain(newGain);
                SetMicrophoneGain(newGain);  // Apply the new gain via WASAPI
                SetWindowText(hGainText, std::to_wstring(newGain).c_str());
            }
            break;

        case WM_HSCROLL:
            if ((HWND)lParam == hSlider) {  // If the slider position changed
                int sliderPos = SendMessage(hSlider, TBM_GETPOS, 0, 0);
                SetWindowText(hGainText, std::to_wstring((float)sliderPos).c_str()); // Display gain value
            }
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// Function to initialize the window with a slider and button
void CreateMainWindow() {
    const wchar_t* className = L"GainControlClass";  // Change to wide-character string
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WindowProc; 
    wc.lpszClassName = className;
    wc.hInstance = GetModuleHandle(NULL);
    
    RegisterClass(&wc);
    
    hWnd = CreateWindowEx(0, className, L"Discord Gain Control", WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, wc.hInstance, NULL);

    // Create a slider for controlling gain (range 0 to 200)
    hSlider = CreateWindowEx(0, TRACKBAR_CLASS, NULL, WS_CHILD | WS_VISIBLE | TBS_HORZ,
                             50, 50, 300, 30, hWnd, NULL, wc.hInstance, NULL);
    SendMessage(hSlider, TBM_SETRANGE, TRUE, MAKELONG(0, 200));  // Range from 0 to 200
    SendMessage(hSlider, TBM_SETPOS, TRUE, (LPARAM)gain);  // Set default value to 100

    // Create a text box to show the current gain value
    hGainText = CreateWindowEx(0, L"STATIC", L"Gain: 100.0", WS_CHILD | WS_VISIBLE,
                               50, 100, 300, 20, hWnd, NULL, wc.hInstance, NULL);

    // Create a button to apply the gain value
    CreateWindowEx(0, L"BUTTON", L"Apply", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                   150, 130, 100, 30, hWnd, (HMENU)1, wc.hInstance, NULL);
}

// Entry point for the DLL
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // Initialize common controls
        INITCOMMONCONTROLSEX icc;
        icc.dwSize = sizeof(icc);
        icc.dwICC = ICC_BAR_CLASSES;
        InitCommonControlsEx(&icc);

        // Inject DLL into Discord process
        InjectDLL(); 

        // Create the main window with the slider and button
        CreateMainWindow();

        // Show the window and start the message loop
        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);

        // Message loop to handle user input
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return TRUE;
}




make the gain work cause when i change the gain its not working and also when i close the gui make it so where it closes discord too