// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#include "blur_shader.h"

#ifdef DRAGONX_HAS_GLAD
#include <glad/gl.h>
#include <cstdio>
#include <vector>
#include "../../util/logger.h"

namespace dragonx {
namespace ui {
namespace effects {

// ============================================================================
// BlurShader Implementation (GLEW Available)
// ============================================================================

BlurShader::BlurShader() = default;

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

bool BlurShader::init()
{
    // Create shaders
    vertexShader_ = glCreateShader(GL_VERTEX_SHADER);
    fragmentShader_ = glCreateShader(GL_FRAGMENT_SHADER);
    
    if (!compileShader(vertexShader_, ShaderSource::BLUR_VERTEX)) {
        DEBUG_LOGF("BlurShader: Failed to compile vertex shader\n");
        destroy();
        return false;
    }
    
    if (!compileShader(fragmentShader_, ShaderSource::BLUR_FRAGMENT)) {
        DEBUG_LOGF("BlurShader: Failed to compile fragment shader\n");
        destroy();
        return false;
    }
    
    // Create program
    program_ = glCreateProgram();
    glAttachShader(program_, vertexShader_);
    glAttachShader(program_, fragmentShader_);
    
    if (!linkProgram()) {
        DEBUG_LOGF("BlurShader: Failed to link program\n");
        destroy();
        return false;
    }
    
    // Get uniform locations
    uTexture_ = glGetUniformLocation(program_, "uTexture");
    uDirection_ = glGetUniformLocation(program_, "uDirection");
    uResolution_ = glGetUniformLocation(program_, "uResolution");
    uRadius_ = glGetUniformLocation(program_, "uRadius");
    
    DEBUG_LOGF("BlurShader: Initialized successfully\n");
    DEBUG_LOGF("  Uniforms: uTexture=%d, uDirection=%d, uResolution=%d, uRadius=%d\n",
           uTexture_, uDirection_, uResolution_, uRadius_);
    
    return true;
}

void BlurShader::destroy()
{
    if (program_) {
        glDeleteProgram(program_);
        program_ = 0;
    }
    if (vertexShader_) {
        glDeleteShader(vertexShader_);
        vertexShader_ = 0;
    }
    if (fragmentShader_) {
        glDeleteShader(fragmentShader_);
        fragmentShader_ = 0;
    }
    
    uTexture_ = -1;
    uDirection_ = -1;
    uResolution_ = -1;
    uRadius_ = -1;
}

bool BlurShader::compileShader(unsigned int shader, const char* source)
{
    glShaderSource(shader, 1, &source, nullptr);
    glCompileShader(shader);
    
    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    
    if (!success) {
        GLint logLength;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
        
        std::vector<char> log(logLength + 1);
        glGetShaderInfoLog(shader, logLength, nullptr, log.data());
        
        DEBUG_LOGF("Shader compile error:\n%s\n", log.data());
        return false;
    }
    
    return true;
}

bool BlurShader::linkProgram()
{
    glLinkProgram(program_);
    
    GLint success;
    glGetProgramiv(program_, GL_LINK_STATUS, &success);
    
    if (!success) {
        GLint logLength;
        glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength);
        
        std::vector<char> log(logLength + 1);
        glGetProgramInfoLog(program_, logLength, nullptr, log.data());
        
        DEBUG_LOGF("Program link error:\n%s\n", log.data());
        return false;
    }
    
    return true;
}

void BlurShader::bind()
{
    glUseProgram(program_);
}

void BlurShader::unbind()
{
    glUseProgram(0);
}

void BlurShader::setDirection(bool horizontal)
{
    if (uDirection_ >= 0) {
        if (horizontal) {
            glUniform2f(uDirection_, 1.0f, 0.0f);
        } else {
            glUniform2f(uDirection_, 0.0f, 1.0f);
        }
    }
}

void BlurShader::setRadius(float radius)
{
    if (uRadius_ >= 0) {
        glUniform1f(uRadius_, radius);
    }
}

void BlurShader::setResolution(int width, int height)
{
    if (uResolution_ >= 0) {
        glUniform2f(uResolution_, static_cast<float>(width), static_cast<float>(height));
    }
}

void BlurShader::setTexture(int unit)
{
    if (uTexture_ >= 0) {
        glUniform1i(uTexture_, unit);
    }
}

// ============================================================================
// FullscreenQuad Implementation
// ============================================================================

FullscreenQuad::FullscreenQuad() = default;

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

bool FullscreenQuad::init()
{
    // Fullscreen quad vertices: position (x,y) and texcoord (u,v)
    // NDC coordinates: -1 to 1
    static const float vertices[] = {
        // Position    // TexCoord
        -1.0f,  1.0f,  0.0f, 1.0f,   // Top-left
        -1.0f, -1.0f,  0.0f, 0.0f,   // Bottom-left
         1.0f, -1.0f,  1.0f, 0.0f,   // Bottom-right
         
        -1.0f,  1.0f,  0.0f, 1.0f,   // Top-left
         1.0f, -1.0f,  1.0f, 0.0f,   // Bottom-right
         1.0f,  1.0f,  1.0f, 1.0f    // Top-right
    };
    
    glGenVertexArrays(1, &vao_);
    glGenBuffers(1, &vbo_);
    
    glBindVertexArray(vao_);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo_);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    // Position attribute (location = 0)
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // TexCoord attribute (location = 1)
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);
    
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    return vao_ != 0;
}

void FullscreenQuad::destroy()
{
    if (vbo_) {
        glDeleteBuffers(1, &vbo_);
        vbo_ = 0;
    }
    if (vao_) {
        glDeleteVertexArrays(1, &vao_);
        vao_ = 0;
    }
}

void FullscreenQuad::draw()
{
    glBindVertexArray(vao_);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}

} // namespace effects
} // namespace ui
} // namespace dragonx

#else // !DRAGONX_HAS_GLAD

// ============================================================================
// Stub Implementation (No GLAD - Acrylic effects disabled)
// ============================================================================

namespace dragonx {
namespace ui {
namespace effects {

BlurShader::BlurShader() = default;
BlurShader::~BlurShader() = default;

bool BlurShader::init() { return false; }
void BlurShader::destroy() {}
bool BlurShader::compileShader(unsigned int, const char*) { return false; }
bool BlurShader::linkProgram() { return false; }
void BlurShader::bind() {}
void BlurShader::unbind() {}
void BlurShader::setDirection(bool) {}
void BlurShader::setRadius(float) {}
void BlurShader::setResolution(int, int) {}
void BlurShader::setTexture(int) {}

FullscreenQuad::FullscreenQuad() = default;
FullscreenQuad::~FullscreenQuad() = default;

bool FullscreenQuad::init() { return false; }
void FullscreenQuad::destroy() {}
void FullscreenQuad::draw() {}

} // namespace effects
} // namespace ui
} // namespace dragonx

#endif // DRAGONX_HAS_GLAD
