#include "D3D.hpp"
#include <SDL.h>
#include <imgui.h>
#include <imgui_impl_dx11.h>
#include <d3d11.h>

namespace Li::Gui {
	void D3D::createRenderTarget() {
		ID3D11Texture2D* backBuffer;
        this->swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
		this->d3dDevice->CreateRenderTargetView(backBuffer, NULL, &this->mainRenderTargetView);
        backBuffer->Release();
	}

	bool D3D::createDeviceD3D() {
            // Setup swap chain
            DXGI_SWAP_CHAIN_DESC sd;
            memset(&sd, 0, sizeof(sd));
            sd.BufferCount = 2;
            sd.BufferDesc.Width = 0;
            sd.BufferDesc.Height = 0;
            sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
            sd.BufferDesc.RefreshRate.Numerator = 60;
            sd.BufferDesc.RefreshRate.Denominator = 1;
            sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
            sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            sd.OutputWindow = this->hwnd;
            sd.SampleDesc.Count = 1;
            sd.SampleDesc.Quality = 0;
            sd.Windowed = TRUE;
            sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

            UINT createDeviceFlags = 0;
            //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
            D3D_FEATURE_LEVEL featureLevel;
            const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
            if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &this->swapChain, &this->d3dDevice, &featureLevel, &this->d3dDeviceContext) != S_OK)
                return false;


            return true;
        }

    void D3D::cleanupDeviceD3D() {
        if (this->swapChain) { 
            this->swapChain->Release();
            this->swapChain = NULL; 
        }

        if (this->d3dDeviceContext) { 
            this->d3dDeviceContext->Release();
            this->d3dDeviceContext = NULL; 
        }

        if (this->d3dDevice) { 
            this->d3dDevice->Release(); 
            this->d3dDevice = NULL; 
        }
    }

	void D3D::cleanupRenderTarget() {
        if (this->mainRenderTargetView) {
            this->mainRenderTargetView->Release(); 
            this->mainRenderTargetView = NULL; 
        }
    }

    ID3D11Device* D3D::D3dDevice() {
        return this->d3dDevice;
    }
    ID3D11DeviceContext* D3D::D3dDeviceContext() {
        return this->d3dDeviceContext;
    }

    void D3D::InitImgui() {
        ImGui_ImplDX11_Init(this->d3dDevice, this->d3dDeviceContext);
    }
    void D3D::ImGuiNewFrame() {
        ImGui_ImplDX11_NewFrame();
    }

    void D3D::Resize() {
        this->cleanupRenderTarget();
        this->swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
        this->createRenderTarget();
    }

    void D3D::Render(ImVec4 clearColor) {
        const float clearColorWithAlpha[4] = { clearColor.x * clearColor.w, clearColor.y * clearColor.w, clearColor.z * clearColor.w, clearColor.w };
        this->d3dDeviceContext->OMSetRenderTargets(1, &this->mainRenderTargetView, NULL);
        this->d3dDeviceContext->ClearRenderTargetView(this->mainRenderTargetView, clearColorWithAlpha);
        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
        this->swapChain->Present(1, 0);
    }

	D3D::D3D(HWND hwnd) {
        this->hwnd = hwnd;
        this->createDeviceD3D();
        this->createRenderTarget();
	};

	D3D::~D3D() {
		this->cleanupRenderTarget();
        this->cleanupDeviceD3D();
	}
}