#pragma once

#include <SDL2/SDL.h>
#include <frostbite2D/types/type_alias.h>
#include <frostbite2D/types/type_math.h>
#include <functional>
#include <string>

namespace frostbite2D {

/**
 * \~chinese
 * @brief 鼠标指针类型
 */
enum class CursorType {
  Arrow,     ///< 指针
  TextInput, ///< 文本
  Hand,      ///< 手
  SizeAll,   ///< 指向四个方向的箭头
  SizeWE,    ///< 指向左右方向的箭头
  SizeNS,    ///< 指向上下方向的箭头
  SizeNESW,  ///< 指向左下到右上方向的箭头
  SizeNWSE,  ///< 指向左上到右下方向的箭头
  No,        ///< 禁止
};

/**
 * \~chinese
 * @brief 分辨率
 */
struct Resolution {
  uint32_t width = 0;        ///< 分辨率宽度
  uint32_t height = 0;       ///< 分辨率高度
  uint32_t refresh_rate = 0; ///< 刷新率

  Resolution() = default;

  Resolution(uint32_t width, uint32_t height, uint32_t refresh_rate)
      : width(width), height(height), refresh_rate(refresh_rate) {}
};

/**
 * \~chinese
 * @brief 图标
 */
struct Icon {
  Icon() = default;

  Icon(std::string file_path) : file_path(file_path) {}

  std::string file_path; ///< 文件路径

#if defined(_WIN32)
  uint32_t resource_id = 0; ///< 资源ID，仅在windows上生效

  Icon(uint32_t resource_id) : resource_id(resource_id) {}
#endif
};

/**
 * \~chinese
 * @brief 窗口设置
 */
struct WindowConfig {
  uint32_t width = 640;                  ///< 窗口宽度
  uint32_t height = 480;                 ///< 窗口高度
  std::string title = "frostbite2D Game"; ///< 窗口标题
  Icon icon;                             ///< 窗口图标
  bool resizable = false;                ///< 窗口大小可调整
  bool fullscreen = false;               ///< 窗口全屏
  bool borderless = false;               ///< 无边框窗口
  bool decorated = true;                 ///< 窗口装饰
  int multisamples = 0;                  ///< 多重采样数
  bool centered = true;                  ///< 窗口是否居中
  bool vsync = true;                     ///< 是否启用垂直同步
  bool showCursor = true;                ///< 是否显示光标
};

class Window {
public:
  Window() = default;
  ~Window() = default;

  /**
   * @brief 创建窗口
   * @param cfg 窗口配置
   * @return 创建是否成功
   */
  virtual bool create(const WindowConfig &cfg);

  /**
   * @brief 销毁窗口
   */
  virtual void destroy();

  /**
   * @brief 轮询事件
   */
  virtual void poll();

  /**
   * @brief 交换缓冲区
   */
  virtual void swap();

  /**
   * @brief 设置窗口关闭标志
   */
  virtual void close();

  /**
   * @brief 设置窗口标题
   */
  virtual void setTitle(const std::string &title);

  /**
   * @brief 设置窗口大小
   */
  virtual void setSize(int w, int h);

  /**
   * @brief 设置窗口位置
   */
  virtual void setPos(int x, int y);

  /**
   * @brief 设置全屏模式
   */
  virtual void setFullscreen(bool fs);

  /**
   * @brief 设置垂直同步
   */
  virtual void setVSync(bool vsync);

  /**
   * @brief 设置窗口可见性
   */
  virtual void setVisible(bool visible);

  /**
   * @brief 获取窗口宽度
   */
  virtual int width() const;

  /**
   * @brief 获取窗口高度
   */
  virtual int height() const;

  /**
   * @brief 获取窗口大小
   */
  virtual Size size() const;

  /**
   * @brief 获取窗口位置
   */
  virtual Vec2 pos() const;

  /**
   * @brief 是否全屏
   */
  virtual bool fullscreen() const;

  /**
   * @brief 是否启用垂直同步
   */
  virtual bool vsync() const;

  /**
   * @brief 窗口是否获得焦点
   */
  virtual bool focused() const;

  /**
   * @brief 窗口是否最小化
   */
  virtual bool minimized() const;

  /**
   * @brief 获取内容缩放X
   */
  virtual float scaleX() const;

  /**
   * @brief 获取内容缩放Y
   */
  virtual float scaleY() const;

  /**
   * @brief 设置光标形状
   */
  virtual void setCursor(CursorType cursor);

  /**
   * @brief 显示/隐藏光标
   */
  virtual void showCursor(bool show);

  /**
   * @brief 锁定/解锁光标
   */
  virtual void lockCursor(bool lock);

  /**
   * @brief 窗口大小改变回调
   */
  using ResizeCb = std::function<void(int, int)>;

  /**
   * @brief 窗口关闭回调
   */
  using CloseCb = std::function<void()>;

  /**
   * @brief 窗口焦点改变回调
   */
  using FocusCb = std::function<void(bool)>;

  /**
   * @brief 设置大小改变回调
   */
  virtual void onResize(ResizeCb cb);

  /**
   * @brief 设置关闭回调
   */
  virtual void onClose(CloseCb cb);

  /**
   * @brief 设置焦点改变回调
   */
  virtual void onFocus(FocusCb cb);

  /**
   * @brief 获取原生窗口句柄
   */
  virtual void *native() const;

  /**
   * @brief 获取 SDL 窗口句柄
   */
  SDL_Window *sdlWindow() const { return sdlWindow_; }

  /**
   * @brief 获取 OpenGL 上下文
   */
  SDL_GLContext glContext() const { return glContext_; }

private:
  SDL_Window *sdlWindow_ = nullptr;
  SDL_GLContext glContext_ = nullptr;

  int width_ = 1280;
  int height_ = 720;
  bool fullscreen_ = false;
  bool vsync_ = true;
  bool focused_ = true;
  bool minimized_ = false;
  bool shouldClose_ = false;
  float scaleX_ = 1.0f;
  float scaleY_ = 1.0f;
  bool cursorVisible_ = true;
  bool cursorLocked_ = false;

  ResizeCb resizeCb_;
  CloseCb closeCb_;
  FocusCb focusCb_;
};

} // namespace frostbite2D