#pragma once

#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif

#include <windows.h>
#include <d3d11.h>
#include <dwmapi.h>
#include <iostream>
#include <string>
#include <cmath>
#include <tlhelp32.h>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx11.h"
#include "imgui/imgui_impl_win32.h"
#include "font_data.h"


inline void StartLootCache();

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dwmapi.lib")


inline HWND handle = nullptr;
inline ID3D11Device* g_pd3dDevice = nullptr;
inline ID3D11DeviceContext* g_pd3dDeviceContext = nullptr;
inline IDXGISwapChain* g_pSwapChain = nullptr;
inline ID3D11RenderTargetView* g_mainRenderTargetView = nullptr;

inline bool g_menuOpen = true;


extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);


enum class OverlayType {
    DISCORD,
    NONE
};

inline OverlayType currentOverlayType = OverlayType::NONE;

inline const char* GetOverlayTypeName(OverlayType type) {
    switch (type) {
        case OverlayType::DISCORD: return "Discord";
        default: return "Unknown";
    }
}

inline HWND hijack() {
    #ifdef _DEBUG
    std::cout << "[DEBUG] ========================================" << std::endl;
    std::cout << "[DEBUG] Starting overlay hijack process..." << std::endl;
    std::cout << "[DEBUG] Searching for Discord overlay..." << std::endl;
    std::cout << "[DEBUG] ========================================" << std::endl;
    #endif
    
    handle = FindWindowA("Chrome_WidgetWin_1", "Discord Overlay");

    while (!handle) {
        #ifdef _DEBUG
        std::cout << "[DEBUG] ✗ Discord overlay not found" << std::endl;
        #endif
        
        std::cout << "[!] Discord overlay not detected" << std::endl;
        
        int result = MessageBoxA(NULL, 
            "Discord overlay not found!\n\n"
            "Please ensure:\n"
            "1. Discord is running\n"
            "2. Overlay is enabled in Discord settings\n"
            "3. In-game overlay is enabled for Fortnite\n\n"
            "Press OK to retry or Cancel to exit.",
            "Overlay Required", 
            MB_OKCANCEL | MB_ICONINFORMATION);
        
        if (result == IDCANCEL) {
            #ifdef _DEBUG
            std::cout << "[DEBUG] User cancelled overlay detection" << std::endl;
            #endif
            currentOverlayType = OverlayType::NONE;
            return nullptr;
        }
        
        #ifdef _DEBUG
        std::cout << "[DEBUG] Retrying overlay detection..." << std::endl;
        #endif
        
        handle = FindWindowA("Chrome_WidgetWin_1", "Discord Overlay");
        if (handle) break;
    }
    
    currentOverlayType = OverlayType::DISCORD;
    
    #ifdef _DEBUG
    std::cout << "[DEBUG] ✓ Found Discord overlay" << std::endl;
    std::cout << "[DEBUG]   Class: Chrome_WidgetWin_1" << std::endl;
    std::cout << "[DEBUG]   Title: Discord Overlay" << std::endl;
    std::cout << "[DEBUG]   HWND: 0x" << std::hex << handle << std::dec << std::endl;
    #endif
    
    std::cout << "[+] Using Discord overlay" << std::endl;
    
    Sleep(100);
    
    if (handle && !IsWindow(handle)) {
        #ifdef _DEBUG
        std::cout << "[DEBUG] ✗ Discord overlay window became invalid, retrying..." << std::endl;
        #endif
        handle = nullptr;
        currentOverlayType = OverlayType::NONE;
        return hijack(); 
    }
    
    return handle;
}

class D3DInit {
public:
    void InitDevices(HWND hWnd) {
        #ifdef _DEBUG
        std::cout << "[DEBUG] Initializing D3D11 devices with performance optimizations..." << std::endl;
        std::cout << "[DEBUG] Using Discord overlay" << std::endl;
        #endif
        
        Sleep(200); 
        
        DXGI_SWAP_CHAIN_DESC sd;
        ZeroMemory(&sd, sizeof(sd));
        
        
        sd.BufferCount = 2;  
        sd.BufferDesc.Width = 0;  
        sd.BufferDesc.Height = 0;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  
        
        
        sd.BufferDesc.RefreshRate.Numerator = 0;  
        sd.BufferDesc.RefreshRate.Denominator = 1;
        
        
        sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
        
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.OutputWindow = hWnd;
        
        
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        
        sd.Windowed = TRUE;
        
        
        sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

        D3D_FEATURE_LEVEL featureLevel;
        const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0 };

        #ifdef _DEBUG
        std::cout << "[DEBUG] Creating D3D11 device with hardware acceleration..." << std::endl;
        #endif

        
        HRESULT res = D3D11CreateDeviceAndSwapChain(
            NULL,                           
            D3D_DRIVER_TYPE_HARDWARE,       
            NULL,                           
            0,                              
            featureLevelArray, 
            2, 
            D3D11_SDK_VERSION, 
            &sd, 
            &g_pSwapChain, 
            &g_pd3dDevice, 
            &featureLevel, 
            &g_pd3dDeviceContext
        );

        if (res != S_OK) {
            #ifdef _DEBUG
            std::cout << "[DEBUG] ✗ First attempt failed (HRESULT: 0x" << std::hex << res << std::dec << "), retrying..." << std::endl;
            #endif
            
            Sleep(1000);
            res = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
            
            if (res != S_OK) {
                #ifdef _DEBUG
                std::cout << "[DEBUG] ✗ Second attempt failed (HRESULT: 0x" << std::hex << res << std::dec << ")" << std::endl;
                #endif
                
                MessageBoxA(NULL, "Failed to create D3D11 device!\n\nPlease ensure your graphics drivers are up to date.", "Error", MB_OK | MB_ICONERROR);
                return;
            }
        }

        #ifdef _DEBUG
        std::cout << "[DEBUG] ✓ D3D11 device created successfully" << std::endl;
        std::cout << "[DEBUG] Feature level: " << (featureLevel == D3D_FEATURE_LEVEL_11_0 ? "11.0" : "10.0") << std::endl;
        std::cout << "[DEBUG] Refresh rate: Unlocked (maximum FPS)" << std::endl;
        #endif

        
        ID3D11Texture2D* pBackBuffer;
        g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
        g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView);
        pBackBuffer->Release();
        
        
        IDXGIDevice1* pDXGIDevice = nullptr;
        if (SUCCEEDED(g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**)&pDXGIDevice))) {
            pDXGIDevice->SetMaximumFrameLatency(1);  
            pDXGIDevice->Release();
            
            #ifdef _DEBUG
            std::cout << "[DEBUG] ✓ Maximum frame latency set to 1 (lowest input lag)" << std::endl;
            #endif
        }
        
        #ifdef _DEBUG
        std::cout << "[DEBUG] ✓ Render target view created" << std::endl;
        std::cout << "[DEBUG] ✓ Performance optimizations applied" << std::endl;
        #endif
    }

    void InitImgui(HWND hWnd) {
        #ifdef _DEBUG
        std::cout << "[DEBUG] Initializing ImGui..." << std::endl;
        #endif
        
        IMGUI_CHECKVERSION();
        ImGui::CreateContext();
        ImGuiIO& io = ImGui::GetIO();

        
        ImFontConfig font_cfg;
        font_cfg.OversampleH = 3;
        font_cfg.OversampleV = 3;
        font_cfg.PixelSnapH = true;
        font_cfg.FontDataOwnedByAtlas = false;

        
        io.Fonts->AddFontFromMemoryTTF((void*)poppins_bold_data, sizeof(poppins_bold_data), 13.0f, &font_cfg);

        
        unsigned char* pixels;
        int width, height;
        io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

        ImGui_ImplWin32_Init(hWnd);
        ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);

        ImGui::StyleColorsDark();
        
        #ifdef _DEBUG
        std::cout << "[DEBUG] ✓ ImGui initialized successfully" << std::endl;
        #endif
    }

    void InitAll() {
        #ifdef _DEBUG
        std::cout << "[DEBUG] ========================================" << std::endl;
        std::cout << "[DEBUG] Starting initialization sequence..." << std::endl;
        std::cout << "[DEBUG] ========================================" << std::endl;
        #endif
        
        handle = hijack();
        
        if (handle) {
            #ifdef _DEBUG
            std::cout << "[DEBUG] ✓ Overlay handle acquired: 0x" << std::hex << handle << std::dec << std::endl;
            std::cout << "[DEBUG] ✓ Overlay type: " << GetOverlayTypeName(currentOverlayType) << std::endl;
            #endif
            
            std::cout << "[+] Initializing rendering engine..." << std::endl;
            
            InitDevices(handle);
            
            if (!g_pd3dDevice || !g_pd3dDeviceContext || !g_pSwapChain) {
                #ifdef _DEBUG
                std::cout << "[DEBUG] ✗ D3D11 initialization failed!" << std::endl;
                #endif
                MessageBoxA(NULL, "Failed to initialize D3D11!", "Error", MB_OK | MB_ICONERROR);
                return;
            }
            
            InitImgui(handle);
            
            #ifdef _DEBUG
            std::cout << "[DEBUG] ========================================" << std::endl;
            std::cout << "[DEBUG] Initialization complete!" << std::endl;
            std::cout << "[DEBUG] Overlay: " << GetOverlayTypeName(currentOverlayType) << std::endl;
            std::cout << "[DEBUG] D3D11 Device: 0x" << std::hex << g_pd3dDevice << std::dec << std::endl;
            std::cout << "[DEBUG] Swap Chain: 0x" << std::hex << g_pSwapChain << std::dec << std::endl;
            std::cout << "[DEBUG] ========================================" << std::endl;
            #endif
            
            std::cout << "[+] Rendering engine ready" << std::endl;
            
            StartLootCache();
        } else {
            #ifdef _DEBUG
            std::cout << "[DEBUG] ✗ Failed to acquire overlay handle" << std::endl;
            #endif
            std::cout << "[!] Failed to initialize overlay" << std::endl;
        }
    }
};

static D3DInit* init = new D3DInit();
