#pragma once

#include <memory>

#include <wrl.h>
#include <d3d12.h>
#include <directx/d3dx12.h>

class DirectXInterface;
class DirectXDescriptors;
class DirectX2dIntegration;
class DirectXBuffers;
class DirectXCommandList;
namespace mt
{
    class Window;
}

struct ID3D12CommandAllocator;
struct ID3D12GraphicsCommandList;
struct IDXGISwapChain4;
struct ID3D12Resource;
struct ID3D12Fence;
struct ID3D12PipelineState;

class Win32DxWindowInterface
{
public:
    Win32DxWindowInterface(mt::Window* window, DirectXInterface* dxInterface);

    ~Win32DxWindowInterface();

    bool initialize();

    void onResize();

    void onRender();

private:
    bool loadAssets();

    void updateCommandList();

    void destroyWindow();

    bool createSwapChain();
    void resizeSwapChain();

    void clearBuffers();
    void populateBuffers();
    void updateBackbufferIndex(UINT index);
  
    void createSyncObjects();
    void flushCommandQueue();

    void updateViewport();

    ID3D12PipelineState* getPipelineState() const;

    DirectXInterface* mDxInterface{ nullptr };
    bool mInitialized{ false };
    bool mIsValid{ false };

    mt::Window* mWindow{ nullptr };
    CD3DX12_VIEWPORT mViewport;
    CD3DX12_RECT mScissorRect;

    std::unique_ptr<DirectXDescriptors> mDescriptors;
    std::unique_ptr<DirectX2dIntegration> mD2dIntegration;
    std::unique_ptr<DirectXBuffers> mBuffers;
    std::unique_ptr<DirectXCommandList> mCommandList;

    Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;

    static const UINT FrameCount = 2;
    Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
    uint64_t mFenceValue = 0;
    uint64_t mFrameFenceValues[FrameCount] = {};
    HANDLE mFenceEvent{};  
};

using XcbGlWindowInterfacePtr = std::unique_ptr<Win32DxWindowInterface>;