#pragma once

#include <SDL3/SDL_gpu.h>

#include <cstdint>
#include <vector>

// ---------------------------------------------------------------------------
// GpuVertex — 8-float vertex layout sent to the GPU.
// Position is in NDC (pre-transformed on CPU), UV in [0,1], color in [0,1].
// ---------------------------------------------------------------------------
struct GpuVertex {
        float x, y;        // NDC position  (−1..1)
        float u, v;        // Texture coords (0..1)
        float r, g, b, a;  // RGBA color     (0..1)
};

// ============================================================================
// GpuSpriteBatch — Accumulates sprite quads, uploads them in one copy pass.
//
// Usage per frame:
//   batch.beginFrame();
//   batch.addBackground(...);       // Must be first (bg indices = [0..5])
//   batch.addSprite(...) × N;
//   batch.uploadBatch(device, cmd); // Copy pass
//   // Then in render pass: bind buffers, draw bg with white tex, draw sprites.
// ============================================================================
class GpuSpriteBatch {
    public:
        // Default maximum sprites (background + UI overlay each count as one sprite)
        static constexpr int DEFAULT_MAX_SPRITES = 200000;

        bool init(SDL_GPUDevice* device, int max_sprites = DEFAULT_MAX_SPRITES);
        void destroy(SDL_GPUDevice* device);

        void beginFrame();

        // Add the full-screen background gradient quad.
        // top_* and bot_* are RGB in [0,1].
        void addBackground(float screen_w, float screen_h, float top_r, float top_g, float top_b, float bot_r, float bot_g, float bot_b);

        // Add a sprite quad (pixel coordinates).
        // scale: uniform scale around the quad centre.
        void addSprite(float x, float y, float w, float h, float r, float g, float b, float a, float scale, float screen_w, float screen_h);

        // Add a full-screen overlay quad (e.g. UI surface, NDC −1..1).
        void addFullscreenOverlay();

        // Upload CPU vectors to GPU buffers via a copy pass.
        // Returns false if the batch is empty.
        bool uploadBatch(SDL_GPUDevice* device, SDL_GPUCommandBuffer* cmd_buf);

        SDL_GPUBuffer* vertexBuffer() const { return vertex_buf_; }
        SDL_GPUBuffer* indexBuffer() const { return index_buf_; }
        int bgIndexCount() const { return bg_index_count_; }
        int overlayIndexOffset() const { return overlay_index_offset_; }
        int overlayIndexCount() const { return overlay_index_count_; }
        int spriteIndexOffset() const { return sprite_index_offset_; }
        int spriteIndexCount() const { return sprite_index_count_; }
        bool isEmpty() const { return vertices_.empty(); }

    private:
        static void toNDC(float px, float py, float screen_w, float screen_h, float& ndx, float& ndy);
        void pushQuad(float ndx0, float ndy0, float ndx1, float ndy1, float u0, float v0, float u1, float v1, float r, float g, float b, float a);

        std::vector<GpuVertex> vertices_;
        std::vector<uint32_t> indices_;

        SDL_GPUBuffer* vertex_buf_ = nullptr;
        SDL_GPUBuffer* index_buf_ = nullptr;
        SDL_GPUTransferBuffer* vertex_transfer_ = nullptr;
        SDL_GPUTransferBuffer* index_transfer_ = nullptr;

        int bg_index_count_ = 0;
        int sprite_index_offset_ = 0;
        int sprite_index_count_ = 0;
        int overlay_index_offset_ = 0;
        int overlay_index_count_ = 0;

        int max_sprites_ = DEFAULT_MAX_SPRITES;
};
