#include "render_target.h"
#include <android/hardware_buffer.h>
#include <glad/egl.h>
#include "logger.h"
bool RenderTarget::create(uint32_t width, uint32_t height)
{
    glGenFramebuffers(1, &m_framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        return false;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    return true;
}

bool RenderTarget::create_exported(uint32_t width, uint32_t height)
{
    AHardwareBuffer_Desc desc = {};
    desc.width = width;
    desc.height = height;
    desc.layers = 1;
    desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
    desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
        AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
        AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
        AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER;

    if (AHardwareBuffer_allocate(&desc, &hardwareBuffer) != 0)
    {
        Logger::Log("Failed to allocate hardware buffer");
        return false;
    }

    EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
    EGLImageKHR eglImage = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
        EGL_NATIVE_BUFFER_ANDROID, clientBuffer, nullptr);

    if (eglImage == EGL_NO_IMAGE_KHR)
    {
        AHardwareBuffer_release(hardwareBuffer);
        Logger::Log("Failed to create EGL image");
        return false;
    }

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);

    eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);

    glGenFramebuffers(1, &m_framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    bool status = (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return status;
}

AHardwareBuffer *RenderTarget::hardware_buffer()
{
    return hardwareBuffer;
}

void RenderTarget::bind()
{
    glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
}

void RenderTarget::unbind()
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void RenderTarget::destroy()
{
    glDeleteTextures(1, &texture);
    glDeleteFramebuffers(1, &m_framebuffer);
}

GLuint RenderTarget::framebuffer() const
{
    return m_framebuffer;
}
