#pragma once

#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/opengl/gl_texture.h>
#include <extra2d/graphics/texture.h>
#include <mutex>

namespace extra2d {

// ============================================================================
// 渲染目标配置
// ============================================================================
struct RenderTargetConfig {
  int width = 800;                              // 宽度
  int height = 600;                             // 高度
  PixelFormat colorFormat = PixelFormat::RGBA8; // 颜色格式
  bool hasDepth = true;                         // 是否包含深度缓冲
  bool hasDepthBuffer = true;                   // 兼容旧API的别名 (同hasDepth)
  bool hasStencil = false;                      // 是否包含模板缓冲
  int samples = 1;                              // 多重采样数 (1 = 无MSAA)
  bool autoResize = true;                       // 是否自动调整大小
};

// ============================================================================
// 渲染目标 - 基于FBO的离屏渲染
// ============================================================================
class RenderTarget {
public:
  RenderTarget();
  ~RenderTarget();

  // 禁止拷贝
  RenderTarget(const RenderTarget &) = delete;
  RenderTarget &operator=(const RenderTarget &) = delete;

  // 允许移动
  RenderTarget(RenderTarget &&other) noexcept;
  RenderTarget &operator=(RenderTarget &&other) noexcept;

  // ------------------------------------------------------------------------
  // 创建和销毁
  // ------------------------------------------------------------------------

  /**
   * @brief 创建渲染目标
   */
  bool create(const RenderTargetConfig &config);

  /**
   * @brief 初始化渲染目标（create的别名，兼容旧API）
   */
  bool init(const RenderTargetConfig &config) { return create(config); }

  /**
   * @brief 从现有纹理创建渲染目标
   */
  bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false);

  /**
   * @brief 销毁渲染目标
   */
  void destroy();

  /**
   * @brief 关闭渲染目标（destroy的别名，兼容旧API）
   */
  void shutdown() { destroy(); }

  /**
   * @brief 检查是否有效
   */
  bool isValid() const { return fbo_ != 0; }

  // ------------------------------------------------------------------------
  // 尺寸和格式
  // ------------------------------------------------------------------------

  int getWidth() const { return width_; }
  int getHeight() const { return height_; }
  Vec2 getSize() const {
    return Vec2(static_cast<float>(width_), static_cast<float>(height_));
  }
  PixelFormat getColorFormat() const { return colorFormat_; }

  // ------------------------------------------------------------------------
  // 绑定和解绑
  // ------------------------------------------------------------------------

  /**
   * @brief 绑定为当前渲染目标
   */
  void bind();

  /**
   * @brief 解绑（恢复默认渲染目标）
   */
  void unbind();

  /**
   * @brief 清除渲染目标
   */
  void clear(const Color &color = Colors::Transparent);

  // ------------------------------------------------------------------------
  // 纹理访问
  // ------------------------------------------------------------------------

  /**
   * @brief 获取颜色纹理
   */
  Ptr<Texture> getColorTexture() const { return colorTexture_; }

  /**
   * @brief 获取深度纹理（如果有）
   */
  Ptr<Texture> getDepthTexture() const { return depthTexture_; }

  // ------------------------------------------------------------------------
  // 视口和裁剪
  // ------------------------------------------------------------------------

  /**
   * @brief 设置视口（相对于渲染目标）
   */
  void setViewport(int x, int y, int width, int height);

  /**
   * @brief 获取完整视口
   */
  void getFullViewport(int &x, int &y, int &width, int &height) const;

  // ------------------------------------------------------------------------
  // 工具方法
  // ------------------------------------------------------------------------

  /**
   * @brief 调整大小（会销毁并重新创建）
   */
  bool resize(int width, int height);

  /**
   * @brief 复制到另一个渲染目标
   */
  void copyTo(RenderTarget &target);

  /**
   * @brief 复制到另一个渲染目标（blitTo的别名，兼容旧API）
   * @param target 目标渲染目标
   * @param color 是否复制颜色缓冲
   * @param depth 是否复制深度缓冲
   */
  void blitTo(RenderTarget &target, bool color = true, bool depth = false);

  /**
   * @brief 复制到屏幕
   */
  void copyToScreen(int screenWidth, int screenHeight);

  /**
   * @brief 保存为图像文件
   */
  bool saveToFile(const std::string &filepath);

  // ------------------------------------------------------------------------
  // 静态方法
  // ------------------------------------------------------------------------

  /**
   * @brief 创建渲染目标的静态工厂方法
   */
  static Ptr<RenderTarget> createFromConfig(const RenderTargetConfig &config);

  /**
   * @brief 获取当前绑定的渲染目标ID
   */
  static GLuint getCurrentFBO();

  /**
   * @brief 绑定默认渲染目标（屏幕）
   */
  static void bindDefault();

  /**
   * @brief 获取FBO ID（供内部使用）
   */
  GLuint getFBO() const { return fbo_; }

protected:
  GLuint fbo_ = 0; // 帧缓冲对象
  GLuint rbo_ = 0; // 渲染缓冲对象（深度/模板）

  Ptr<Texture> colorTexture_; // 颜色纹理
  Ptr<Texture> depthTexture_; // 深度纹理（可选）

  int width_ = 0;
  int height_ = 0;
  PixelFormat colorFormat_ = PixelFormat::RGBA8;
  bool hasDepth_ = false;
  bool hasStencil_ = false;
  int samples_ = 1;

  bool createFBO();
  void deleteFBO();
};

// ============================================================================
// 多重采样渲染目标（用于MSAA）
// ============================================================================
class MultisampleRenderTarget : public RenderTarget {
public:
  /**
   * @brief 创建多重采样渲染目标
   */
  bool create(int width, int height, int samples = 4);

  /**
   * @brief 解析到普通渲染目标（用于显示）
   */
  void resolveTo(RenderTarget &target);

  /**
   * @brief 销毁渲染目标
   */
  void destroy();

private:
  GLuint colorRBO_ = 0; // 多重采样颜色渲染缓冲
};

// ============================================================================
// 渲染目标栈（用于嵌套渲染）
// ============================================================================
class RenderTargetStack {
public:
  static RenderTargetStack &getInstance();

  /**
   * @brief 压入渲染目标
   */
  void push(RenderTarget *target);

  /**
   * @brief 弹出渲染目标
   */
  void pop();

  /**
   * @brief 获取当前渲染目标
   */
  RenderTarget *getCurrent() const;

  /**
   * @brief 获取栈大小
   */
  size_t size() const;

  /**
   * @brief 清空栈
   */
  void clear();

private:
  RenderTargetStack() = default;
  ~RenderTargetStack() = default;

  std::vector<RenderTarget *> stack_;
  mutable std::mutex mutex_;
};

// ============================================================================
// 渲染目标管理器 - 全局渲染目标管理
// ============================================================================
class RenderTargetManager {
public:
  /**
   * @brief 获取单例实例
   */
  static RenderTargetManager &getInstance();

  /**
   * @brief 初始化渲染目标管理器
   * @param width 默认宽度
   * @param height 默认高度
   */
  bool init(int width, int height);

  /**
   * @brief 关闭渲染目标管理器
   */
  void shutdown();

  /**
   * @brief 创建新的渲染目标
   */
  Ptr<RenderTarget> createRenderTarget(const RenderTargetConfig &config);

  /**
   * @brief 获取默认渲染目标
   */
  RenderTarget *getDefaultRenderTarget() const {
    return defaultRenderTarget_.get();
  }

  /**
   * @brief 调整所有受管渲染目标的大小
   */
  void resize(int width, int height);

  /**
   * @brief 检查是否已初始化
   */
  bool isInitialized() const { return initialized_; }

private:
  RenderTargetManager() = default;
  ~RenderTargetManager() = default;
  RenderTargetManager(const RenderTargetManager &) = delete;
  RenderTargetManager &operator=(const RenderTargetManager &) = delete;

  Ptr<RenderTarget> defaultRenderTarget_;
  std::vector<Ptr<RenderTarget>> renderTargets_;
  bool initialized_ = false;
};

// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::getInstance()
#define E2D_RENDER_TARGET_MANAGER()                                            \
  ::extra2d::RenderTargetManager::getInstance()

} // namespace extra2d
