#pragma once

#include <SDL3/SDL_gpu.h>

// ============================================================================
// PostFXUniforms — pushed to the fragment stage each frame via
//   SDL_PushGPUFragmentUniformData(pass, 0, &uniforms, sizeof(PostFXUniforms))
// MSL binding: constant PostFXUniforms& u [[buffer(0)]]
// ============================================================================
struct PostFXUniforms {
        float vignette_strength;  // 0 = none, 0.8 = default subtle
        float chroma_strength;    // 0 = off, 0.2 = default chromatic aberration
        float scanline_strength;  // 0 = off, 1 = full scanlines
        float screen_height;      // logical render target height (px), for resolution-independent scanlines
};

// ============================================================================
// GpuPipeline — Creates and owns the graphics pipelines used by the engine.
//
//  sprite_pipeline_ : textured quads, alpha blending.
//                     Vertex layout: GpuVertex (pos float2, uv float2, col float4).
//  ball_pipeline_   : instanced ball rendering, alpha blending.
//                     Vertex layout: BallGPUData as per-instance data (input_rate=INSTANCE).
//                     6 procedural vertices per instance (no index buffer).
//  postfx_pipeline_ : full-screen triangle, no vertex buffer, no blend.
//                     Reads offscreen texture, writes to swapchain.
//                     Accepts PostFXUniforms via fragment uniform buffer slot 0.
// ============================================================================
class GpuPipeline {
    public:
        // target_format: pass SDL_GetGPUSwapchainTextureFormat() result.
        // offscreen_format: format of the offscreen render target.
        bool init(SDL_GPUDevice* device,
            SDL_GPUTextureFormat target_format,
            SDL_GPUTextureFormat offscreen_format);
        void destroy(SDL_GPUDevice* device);

        SDL_GPUGraphicsPipeline* spritePipeline() const { return sprite_pipeline_; }
        SDL_GPUGraphicsPipeline* ballPipeline() const { return ball_pipeline_; }
        SDL_GPUGraphicsPipeline* postfxPipeline() const { return postfx_pipeline_; }

    private:
        static SDL_GPUShader* createShader(SDL_GPUDevice* device,
            const char* msl_source,
            const char* entrypoint,
            SDL_GPUShaderStage stage,
            Uint32 num_samplers,
            Uint32 num_uniform_buffers,
            Uint32 num_storage_buffers = 0);

        static SDL_GPUShader* createShaderSPIRV(SDL_GPUDevice* device,
            const uint8_t* spv_code,
            size_t spv_size,
            const char* entrypoint,
            SDL_GPUShaderStage stage,
            Uint32 num_samplers,
            Uint32 num_uniform_buffers,
            Uint32 num_storage_buffers = 0);

        SDL_GPUGraphicsPipeline* sprite_pipeline_ = nullptr;
        SDL_GPUGraphicsPipeline* ball_pipeline_ = nullptr;
        SDL_GPUGraphicsPipeline* postfx_pipeline_ = nullptr;
};
