#pragma once

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#include <android/hardware_buffer.h>

/**
 * EGL context for importing HardwareBuffers and blitting to encoder Surface.
 * Handles EGL setup, HardwareBuffer→EGLImage→texture import, and fence sync.
 */
class EglContext {
public:
    EglContext();
    ~EglContext();

    /** Initialize EGL with a recordable config. Returns true on success. */
    bool Init();

    /** Create a window surface from an ANativeWindow (encoder input surface). */
    bool CreateWindowSurface(ANativeWindow* window);

    /** Import a HardwareBuffer as a GL texture. Returns texture ID (0 on failure). */
    GLuint ImportHardwareBuffer(AHardwareBuffer* buffer);

    /** Release a previously imported HardwareBuffer texture. */
    void ReleaseImportedTexture(GLuint textureId, EGLImageKHR image);

    /** Wait on a native GPU fence FD. Takes ownership of the FD. */
    void WaitFence(int fenceFd);

    /** Set presentation time on the current surface. */
    void SetPresentationTime(int64_t timestampNs);

    /** Make the window surface current. */
    bool MakeCurrent();

    /** Swap buffers on the window surface. */
    bool SwapBuffers();

    /** Create a preview surface from an ANativeWindow. Shares the same EGLContext. */
    bool CreatePreviewSurface(ANativeWindow* window);

    /** Destroy the preview surface. */
    void DestroyPreviewSurface();

    /** Make the preview surface current. */
    bool MakePreviewCurrent();

    /** Make the encoder surface current (restores after preview). */
    bool MakeEncoderCurrent();

    /** Swap buffers on the preview surface. */
    bool SwapPreviewBuffers();

    bool HasPreviewSurface() const { return previewSurface != EGL_NO_SURFACE; }
    int GetPreviewWidth() const { return previewWidth; }
    int GetPreviewHeight() const { return previewHeight; }

    /** Release all EGL resources. */
    void Release();

    EGLDisplay GetDisplay() const { return display; }
    int GetWidth() const { return surfaceWidth; }
    int GetHeight() const { return surfaceHeight; }

private:
    EGLDisplay display = EGL_NO_DISPLAY;
    EGLContext context = EGL_NO_CONTEXT;
    EGLSurface surface = EGL_NO_SURFACE;
    EGLConfig config = nullptr;

    int surfaceWidth = 0;
    int surfaceHeight = 0;

    // Preview surface (shares EGLContext with encoder surface)
    EGLSurface previewSurface = EGL_NO_SURFACE;
    ANativeWindow* previewWindow = nullptr;
    int previewWidth = 0;
    int previewHeight = 0;

    // Extension function pointers
    PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
    PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
    PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
    PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC eglGetNativeClientBufferANDROID = nullptr;
    PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
    PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
    PFNEGLPRESENTATIONTIMEANDROIDPROC eglPresentationTimeANDROID = nullptr;

    bool LoadExtensions();
};
