#pragma once

#include "RenderSystem.h"
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <chrono>

#include <glad/glad.h>

namespace Vivid2D::Render::Texture {

    // ==================== 枚举定义 ====================

    enum class VIVID_2D_MYDLL_API TextureFormat {
        RED,
        RG,
        RGB,
        RGBA,
        ALPHA,
        LUMINANCE,
        LUMINANCE_ALPHA,
    };

    enum class VIVID_2D_MYDLL_API TextureType {
        UNSIGNED_BYTE,
        BYTE,
        UNSIGNED_SHORT,
        SHORT,
        UNSIGNED_INT,
        INT,
        FLOAT,
    };

    enum class VIVID_2D_MYDLL_API TextureFilter {
        NEAREST,
        LINEAR,
        NEAREST_MIPMAP_NEAREST,
        LINEAR_MIPMAP_NEAREST,
        NEAREST_MIPMAP_LINEAR,
        LINEAR_MIPMAP_LINEAR,
    };

    enum class VIVID_2D_MYDLL_API TextureWrap {
        REPEAT,
        MIRRORED_REPEAT,
        CLAMP_TO_EDGE,
        CLAMP_TO_BORDER,
    };

    // ==================== 辅助函数和结构体 ====================

    // 将枚举转换为对应的 OpenGL GLenum 值
    GLint getGLInternalFormat(TextureFormat format);
    GLenum getGLFormat(TextureFormat format);
    GLenum getGLType(TextureType type);
    GLint getGLFilter(TextureFilter filter);
    GLint getGLWrap(TextureWrap wrap);
    int getComponentCount(TextureFormat format);
    TextureFormat getTextureFormatFromComponents(int components);


    /**
     * @brief 存储从文件中加载的原始图像数据
     */
    struct VIVID_2D_MYDLL_API ImageData {
        std::unique_ptr<unsigned char, void(*)(void*)> data;
        int width;
        int height;
        TextureFormat format;
        std::string sourcePath;

        ImageData(unsigned char* d, int w, int h, TextureFormat f, std::string path);
    };

    /**
     * @brief 存储图像文件的元数据，而不加载整个图像
     */
    struct VIVID_2D_MYDLL_API ImageInfo {
        int width;
        int height;
        int components;
        std::string filePath;
    };

    /**
     * @class Texture
     * @brief 使用 OpenGL API 实现完整的纹理管理
     */
    class VIVID_2D_MYDLL_API Texture {
    public:
        // ==================== 构造函数、析构函数和移动语义 ====================

        /**
         * @brief 创建一个空的纹理对象，准备接收数据。
         */
        Texture(std::string name, int width, int height, TextureFormat format, TextureType type = TextureType::UNSIGNED_BYTE);

        /**
         * @brief 从给定的像素数据创建一个纹理。
         */
        Texture(std::string name, int width, int height, TextureFormat format, const unsigned char* pixelData);

        ~Texture();

        // 纹理是唯一的资源，应禁止拷贝，但允许移动
        Texture(const Texture&) = delete;
        Texture& operator=(const Texture&) = delete;
        Texture(Texture&& other) noexcept;
        Texture& operator=(Texture&& other) noexcept;

        // ==================== 纹理数据管理 ====================

        /**
         * @brief 上传像素数据到 GPU。
         * @param pixelData 指向像素数据的指针。
         */
        void uploadData(const std::vector<unsigned char>& pixelData);
        void uploadData(const unsigned char* pixelData, size_t size);

        /**
         * @brief 为纹理生成 Mipmap。
         */
        void generateMipmaps();

        /**
         * @brief 从当前纹理裁剪出一个子纹理并返回新的 Texture 实例。
         */
        std::unique_ptr<Texture> crop(int x, int y, int w, int h, const std::string& newName);

        // ==================== 纹理参数设置 ====================

        void setMinFilter(TextureFilter filter);
        void setMagFilter(TextureFilter filter);
        void setWrapS(TextureWrap wrap);
        void setWrapT(TextureWrap wrap);
        void setWrap(TextureWrap wrapS, TextureWrap wrapT);
        void setWrap(TextureWrap wrap);

        // ==================== 绑定管理 ====================

        void bind(int textureUnit = 0) const;
        void unbind() const;

        // ==================== 资源管理 ====================

        void dispose();
        bool isDisposed() const;

        // ==================== 像素数据缓存支持 ====================

        bool hasPixelData() const;
        std::vector<unsigned char> getPixelData();
        void setPixelData(const std::vector<unsigned char>& data);
        void clearPixelDataCache();
        void ensurePixelDataCached();
        size_t getPixelDataCacheSize() const;

        /**
         * @brief 从 GPU 提取纹理数据。
         */
        std::vector<unsigned char> extractTextureData();

        /**
         * @brief 将纹理保存到文件。
         * @param filePath 保存路径。
         * @param format 文件格式 ("png", "jpg", "bmp", "tga")。
         */
        bool saveToFile(const std::string& filePath, const std::string& format = "png");

        /**
         * @brief 创建此纹理的深拷贝。
         */
        std::unique_ptr<Texture> copy(const std::string& newName) const;


        // ==================== Getter 方法 ====================

        GLuint getTextureId() const { return m_TextureId; }
        const std::string& getName() const { return m_Name; }
        int getWidth() const { return m_Width; }
        int getHeight() const { return m_Height; }
        TextureFormat getFormat() const { return m_Format; }
        TextureType getType() const { return m_Type; }
        TextureFilter getMinFilter() const { return m_MinFilter; }
        TextureFilter getMagFilter() const { return m_MagFilter; }
        TextureWrap getWrapS() const { return m_WrapS; }
        TextureWrap getWrapT() const { return m_WrapT; }
        bool isMipmapsEnabled() const { return m_MipmapsEnabled; }
        long long getCreationTime() const { return m_CreationTime; }
        long getEstimatedMemoryUsage() const;


        // ==================== 静态工厂方法 ====================

        static std::shared_ptr<Texture> createSolidColor(const std::string& name, int width, int height, uint32_t rgbaColor);
        static std::shared_ptr<Texture> createCheckerboard(const std::string& name, int width, int height, int tileSize, uint32_t color1, uint32_t color2);
        static std::shared_ptr<Texture> getOrCreate(const std::string& name, int width, int height, TextureFormat format);
        static std::unique_ptr<ImageData> loadImageFromFile(const std::string& filePath);
        static std::shared_ptr<Texture> createFromFile(const std::string& name, const std::string& filePath, TextureFilter minFilter = TextureFilter::LINEAR, TextureFilter magFilter = TextureFilter::LINEAR);
        static std::shared_ptr<Texture> createFromBytes(const std::string& name, const std::vector<unsigned char>& imageData, TextureFilter minFilter = TextureFilter::LINEAR, TextureFilter magFilter = TextureFilter::LINEAR);

        /**
         * @brief 从 ARGB 格式的原始像素数据创建纹理（例如来自 AWT/Swing 或其他库）。
         * @param pixels 指向 32-bit ARGB 像素数据的指针。
         * @param isPremultiplied Alpha 是否已预乘。
         */
        static std::shared_ptr<Texture> createFromARGB(const std::string& name, int width, int height, const uint32_t* pixels, bool isPremultiplied, TextureFilter minFilter = TextureFilter::LINEAR, TextureFilter magFilter = TextureFilter::LINEAR);

        // ==================== 静态工具方法 ====================

        static bool isSupportedImageFormat(const std::string& filePath);
        static ImageInfo getImageInfo(const std::string& filePath);
        static void cleanupAll();
        static void stbi_vertical_flip_on_load(bool flip);

    private:
        // ==================== 私有成员变量 ====================
        GLuint m_TextureId = 0;
        std::string m_Name;
        int m_Width = 0;
        int m_Height = 0;
        TextureFormat m_Format;
        TextureType m_Type;

        TextureFilter m_MinFilter = TextureFilter::LINEAR;
        TextureFilter m_MagFilter = TextureFilter::LINEAR;
        TextureWrap m_WrapS = TextureWrap::CLAMP_TO_EDGE;
        TextureWrap m_WrapT = TextureWrap::CLAMP_TO_EDGE;
        bool m_MipmapsEnabled = false;

        bool m_Disposed = false;
        long long m_CreationTime; // 使用 steady_clock 或 system_clock

        std::vector<unsigned char> m_PixelDataCache;

        // ==================== 静态管理 ====================
        static std::unordered_map<std::string, std::weak_ptr<Texture>> s_TextureCache;
        static std::mutex s_CacheMutex;

        // ==================== 私有方法 ====================
        void createTextureObject();
        void applyTextureParameters();
        void cachePixelDataFromGPU();
        static GLuint generateTextureId();
        static bool isPowerOfTwo(int value);
    };

} // namespace Vivid2D::Texture
