#include "renderpass.h"

#include "passes/background.h"
#include "passes/geometry.h"
#include "passes/imgui_pass.h"
#include "passes/lighting.h"
#include "passes/ssr.h"
#include "passes/particles.h"
#include "passes/fxaa.h"
#include "passes/transparent.h"
#include "passes/tonemap.h"
#include "passes/shadow.h"

void RenderPassManager::init(EngineContext *context)
{
    _context = context;

    auto backgroundPass = std::make_unique<BackgroundPass>();
    backgroundPass->init(context);
    addPass(std::move(backgroundPass));

    // Shadow map pass comes early in the frame
    auto shadowPass = std::make_unique<ShadowPass>();
    shadowPass->init(context);
    addPass(std::move(shadowPass));

    auto geometryPass = std::make_unique<GeometryPass>();
    geometryPass->init(context);
    addPass(std::move(geometryPass));

    auto lightingPass = std::make_unique<LightingPass>();
    lightingPass->init(context);
    addPass(std::move(lightingPass));

    // Screen Space Reflections pass (wired between lighting and transparent)
    auto ssrPass = std::make_unique<SSRPass>();
    ssrPass->init(context);
    addPass(std::move(ssrPass));

    // GPU particle system (compute update + render)
    auto particlePass = std::make_unique<ParticlePass>();
    particlePass->init(context);
    addPass(std::move(particlePass));

    // Post-process AA (FXAA-like) after tonemapping.
    auto fxaaPass = std::make_unique<FxaaPass>();
    fxaaPass->init(context);
    addPass(std::move(fxaaPass));

    auto transparentPass = std::make_unique<TransparentPass>();
    transparentPass->init(context);
    addPass(std::move(transparentPass));

    auto tonemapPass = std::make_unique<TonemapPass>();
    tonemapPass->init(context);
    addPass(std::move(tonemapPass));
}

void RenderPassManager::cleanup()
{
    for (auto &pass: _passes)
    {
        pass->cleanup();
    }
    if (_imguiPass)
    {
        _imguiPass->cleanup();
    }
    fmt::print("RenderPassManager::cleanup()\n");
    _passes.clear();
    _imguiPass.reset();
}

void RenderPassManager::addPass(std::unique_ptr<IRenderPass> pass)
{
    _passes.push_back(std::move(pass));
}

void RenderPassManager::setImGuiPass(std::unique_ptr<IRenderPass> imguiPass)
{
    _imguiPass = std::move(imguiPass);
    if (_imguiPass)
    {
        _imguiPass->init(_context);
    }
}

ImGuiPass *RenderPassManager::getImGuiPass()
{
    if (!_imguiPass) return nullptr;
    return dynamic_cast<ImGuiPass *>(_imguiPass.get());
}
