// gpu_postfx_pipeline.cpp - Implementación del pipeline de postprocesado.

#include "core/rendering/gpu/gpu_postfx_pipeline.hpp"

#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>

#include <iostream>

#include "core/rendering/gpu/gpu_device.hpp"

namespace Rendering::GPU {

GpuPostFxPipeline::~GpuPostFxPipeline() { destroy(); }

auto GpuPostFxPipeline::init(const GpuDevice& device,
                             SDL_GPUTextureFormat target_format) -> bool {
    owner_ = device.get();
    if (owner_ == nullptr) {
        return false;
    }

    // El vertex shader no usa UBO (emite tres vértices hardcodeados).
    // El fragment shader usa 1 sampler (escena) y 1 UBO (parámetros postpro).
    SDL_GPUShader* vert = device.loadShader("postfx.vert.spv",
                                            SDL_GPU_SHADERSTAGE_VERTEX,
                                            /*num_uniform_buffers=*/0,
                                            /*num_samplers=*/0);
    SDL_GPUShader* frag = device.loadShader("postfx.frag.spv",
                                            SDL_GPU_SHADERSTAGE_FRAGMENT,
                                            /*num_uniform_buffers=*/1,
                                            /*num_samplers=*/1);
    if ((vert == nullptr) || (frag == nullptr)) {
        if (vert != nullptr) {
            SDL_ReleaseGPUShader(owner_, vert);
        }
        if (frag != nullptr) {
            SDL_ReleaseGPUShader(owner_, frag);
        }
        std::cerr << "[GpuPostFxPipeline] Error cargando shaders postfx\n";
        return false;
    }

    // Sin vertex input: los tres vértices del triángulo se generan en el shader.
    SDL_GPUVertexInputState vertex_input{};
    vertex_input.vertex_buffer_descriptions = nullptr;
    vertex_input.num_vertex_buffers = 0;
    vertex_input.vertex_attributes = nullptr;
    vertex_input.num_vertex_attributes = 0;

    // Color target del postpro = swapchain. Sin blending: el postpro reescribe
    // píxeles directamente (la mezcla con la escena ya se hizo dentro del shader).
    SDL_GPUColorTargetDescription color_target{};
    color_target.format = target_format;
    color_target.blend_state.enable_blend = false;
    color_target.blend_state.color_write_mask =
        SDL_GPU_COLORCOMPONENT_R | SDL_GPU_COLORCOMPONENT_G |
        SDL_GPU_COLORCOMPONENT_B | SDL_GPU_COLORCOMPONENT_A;

    SDL_GPUGraphicsPipelineTargetInfo target_info{};
    target_info.color_target_descriptions = &color_target;
    target_info.num_color_targets = 1;
    target_info.has_depth_stencil_target = false;

    SDL_GPUGraphicsPipelineCreateInfo info{};
    info.vertex_shader = vert;
    info.fragment_shader = frag;
    info.vertex_input_state = vertex_input;
    info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
    info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
    info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
    info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
    info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
    info.depth_stencil_state = {};
    info.target_info = target_info;

    pipeline_ = SDL_CreateGPUGraphicsPipeline(owner_, &info);

    SDL_ReleaseGPUShader(owner_, vert);
    SDL_ReleaseGPUShader(owner_, frag);

    if (pipeline_ == nullptr) {
        std::cerr << "[GpuPostFxPipeline] SDL_CreateGPUGraphicsPipeline: "
                  << SDL_GetError() << '\n';
        return false;
    }
    return true;
}

void GpuPostFxPipeline::destroy() {
    if ((pipeline_ != nullptr) && (owner_ != nullptr)) {
        SDL_ReleaseGPUGraphicsPipeline(owner_, pipeline_);
    }
    pipeline_ = nullptr;
    owner_ = nullptr;
}

}  // namespace Rendering::GPU
