#pragma once

#include <extra2d/core/types.h>
#include <extra2d/graphics/texture.h>
#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <unordered_map>

namespace extra2d {

// ============================================================================
// 纹理池配置
// ============================================================================
struct TexturePoolConfig {
  size_t maxCacheSize = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
  size_t maxTextureCount = 256;           // 最大纹理数量
  float unloadInterval = 30.0f;           // 自动清理间隔 (秒)
  bool enableAsyncLoad = true;            // 启用异步加载
};

// ============================================================================
// 纹理池 - 使用LRU缓存策略管理纹理复用
// ============================================================================
class TexturePool {
public:
  // ------------------------------------------------------------------------
  // 单例访问
  // ------------------------------------------------------------------------
  static TexturePool &getInstance();

  // ------------------------------------------------------------------------
  // 初始化和关闭
  // ------------------------------------------------------------------------
  bool init(const TexturePoolConfig &config = TexturePoolConfig{});
  void shutdown();

  // ------------------------------------------------------------------------
  // 纹理获取
  // ------------------------------------------------------------------------

  /**
   * @brief 从文件获取纹理（带缓存）
   * @param filepath 纹理文件路径
   * @return 纹理对象，失败返回nullptr
   */
  Ptr<Texture> get(const std::string &filepath);

  /**
   * @brief 异步加载纹理
   * @param filepath 纹理文件路径
   * @param callback 加载完成回调
   */
  void getAsync(const std::string &filepath,
                std::function<void(Ptr<Texture>)> callback);

  /**
   * @brief 从内存数据创建纹理（自动缓存）
   * @param name 纹理名称（用于缓存键）
   * @param data 图像数据
   * @param width 宽度
   * @param height 高度
   * @param format 像素格式
   * @return 纹理对象
   */
  Ptr<Texture> createFromData(const std::string &name, const uint8_t *data,
                              int width, int height,
                              PixelFormat format = PixelFormat::RGBA8);

  // ------------------------------------------------------------------------
  // 缓存管理
  // ------------------------------------------------------------------------

  /**
   * @brief 手动添加纹理到缓存
   */
  void add(const std::string &key, Ptr<Texture> texture);

  /**
   * @brief 从缓存移除纹理
   */
  void remove(const std::string &key);

  /**
   * @brief 检查纹理是否在缓存中
   */
  bool has(const std::string &key) const;

  /**
   * @brief 清空所有缓存
   */
  void clear();

  /**
   * @brief 清理未使用的纹理（LRU策略）
   * @param targetSize 目标缓存大小
   */
  void trim(size_t targetSize);

  // ------------------------------------------------------------------------
  // 统计信息
  // ------------------------------------------------------------------------

  /**
   * @brief 获取当前缓存的纹理数量
   */
  size_t getTextureCount() const;

  /**
   * @brief 获取当前缓存的总大小（字节）
   */
  size_t getCacheSize() const;

  /**
   * @brief 获取缓存命中率
   */
  float getHitRate() const;

  /**
   * @brief 打印统计信息
   */
  void printStats() const;

  // ------------------------------------------------------------------------
  // 自动清理
  // ------------------------------------------------------------------------

  /**
   * @brief 更新（在主循环中调用，用于自动清理）
   */
  void update(float dt);

  /**
   * @brief 设置自动清理间隔
   */
  void setAutoUnloadInterval(float interval);

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

  // 侵入式LRU节点 - 减少内存分配和指针跳转
  struct LRUNode {
    std::string key;
    uint32_t prev;  // 数组索引，0表示无效
    uint32_t next;  // 数组索引，0表示无效
    bool valid = false;
  };

  // 缓存项 - 紧凑存储
  struct CacheEntry {
    Ptr<Texture> texture;
    size_t size;          // 纹理大小（字节）
    float lastAccessTime; // 最后访问时间
    uint32_t accessCount; // 访问次数
    uint32_t lruIndex;    // LRU节点索引
  };

  mutable std::mutex mutex_;
  TexturePoolConfig config_;

  // 缓存存储
  std::unordered_map<std::string, CacheEntry> cache_;

  // 侵入式LRU链表 - 使用数组索引代替指针，提高缓存局部性
  std::vector<LRUNode> lruNodes_;
  uint32_t lruHead_ = 0;  // 最近使用
  uint32_t lruTail_ = 0;  // 最久未使用
  uint32_t freeList_ = 0; // 空闲节点链表

  // 统计
  size_t totalSize_ = 0;
  uint64_t hitCount_ = 0;
  uint64_t missCount_ = 0;
  float autoUnloadTimer_ = 0.0f;
  bool initialized_ = false;

  // 异步加载队列
  struct AsyncLoadTask {
    std::string filepath;
    std::function<void(Ptr<Texture>)> callback;
  };
  std::vector<AsyncLoadTask> asyncTasks_;

  // LRU操作
  uint32_t allocateLRUNode(const std::string& key);
  void freeLRUNode(uint32_t index);
  void moveToFront(uint32_t index);
  void removeFromList(uint32_t index);
  std::string evictLRU();

  // 内部方法
  void touch(const std::string &key);
  void evict();
  Ptr<Texture> loadTexture(const std::string &filepath);
  size_t calculateTextureSize(int width, int height, PixelFormat format);
  void processAsyncTasks();
};

// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_TEXTURE_POOL() ::extra2d::TexturePool::getInstance()

} // namespace extra2d
