#pragma once
#include "bgfx/defines.h"
#include <bgfx/bgfx.h>
#include <bx/string.h>
#include <cstdint>

#include "../Global.h"
#include "imgui.h"

union SDL_Event;

namespace Game
{
    struct PosColorVertex
    {
        float x;
        float y;
        float z;
        float n_x;
        float n_y;
        float n_z;
        uint32_t abgr;
        float uv_x;
        float uv_y;
    };

    struct Texture
    {
        bgfx::UniformHandle SamplerHandle;
        bgfx::TextureHandle Handle;
        bgfx::TextureInfo Info;
    };

    struct Model
    {
        bgfx::VertexBufferHandle VertexBuffer;
        bgfx::IndexBufferHandle IndexBuffer;
        bgfx::VertexLayout VertLayout;
        uint32_t AssetHandle = UINT16_MAX;
    };

    struct Material
    {
        enum UniformNames : uint32_t
        {
            UTime = 0,
            UDotColor = 1,
            UTexInfo = 2,
            UBaseColor = 3,
        };

        bgfx::ProgramHandle Shader;
        bgfx::UniformHandle Uniforms[8];
        Texture Textures[4];
        uint64_t State = 0;
        uint32_t ViewID = 0;
        static Material LoadFromShader(const char* vertPath,
                                       const char* fragPath,
                                       uint16_t view,
                                       bgfx::TextureHandle = BGFX_INVALID_HANDLE,
                                       bgfx::UniformHandle sampler = BGFX_INVALID_HANDLE);
    };

    enum class UIVisibilityState
    {
        None,
        Game,
        Debug,
    };

    struct DitherData
    {
        static constexpr uint32_t BrightnessBucketCount = 256;
        Vec2 Points[4096];
        uint32_t PointCount = 0;
        Vec4 DitherTex[256 * 256 * 64];
        uint32_t DitherTexWH = 0;
        uint32_t DitherTexDepth = 0;
        int32_t BrightnessBuckets[BrightnessBucketCount];
        float BrightnessRamp[BrightnessBucketCount + 1];
        bgfx::TextureHandle PreviewTex = BGFX_INVALID_HANDLE;
        bgfx::TextureHandle FinalTex = BGFX_INVALID_HANDLE;
        bgfx::TextureHandle RampTex = BGFX_INVALID_HANDLE;

        bgfx::UniformHandle DitherSampler = BGFX_INVALID_HANDLE;
        bgfx::UniformHandle RampSampler = BGFX_INVALID_HANDLE;
        ImTextureID PreviewID = 0;
    };

    class GameRendering
    {
      public:
        static constexpr uint32_t MaxModels = 64;
        static GameRendering& Get();

      public:
        UIVisibilityState UIVisible = UIVisibilityState::Game;
        DitherData DitherTextures;

      public:
        bgfx::UniformHandle DefaultSampler;
        Texture Textures[8];
        Material Materials[8];
        uint32_t ModelCount = 0;
        Model Models[MaxModels];
        int32_t LastWidth = 0;
        int32_t LastHeight = 0;
        uint32_t ResetFlags = BGFX_RESET_NONE;
        uint16_t MainViewID = 10;
        float LastShaderLoadTime = 0.0f;
        int32_t DitherRecursion = 1;
        Vec4 DefaultBaseColor;
        Vec4 DefaultTileColor;

      public:
        void Setup();
        void Update();
        void HandleEvents();
        void RenderDebugUI();
        void Shutdown();
        uint16_t GetModelHandleFromPath(const char* path);
    };
} // namespace Game
