#pragma once

#include <SDL.h>
#include <core/service.h>
#include <string>
#include <types/base/types.h>
#include <types/math/size.h>
#include <types/math/vec2.h>
#include <types/ptr/ref_counted.h>

namespace extra2d {

/**
 * @brief 窗口配置
 */
struct WindowCfg {
  std::string title = "Extra2D";
  int32 width = 1280;
  int32 height = 720;
  bool fullscreen = false;
  bool resizable = true;
  bool vsync = true;
  int32 glMajor = 3;
  int32 glMinor = 3;
};

/**
 * @brief 窗口事件回调
 */
using ResizeCb = Fn<void(int32 w, int32 h)>;
using CloseCb = Fn<void()>;

/**
 * @brief 窗口服务
 *
 * 管理 SDL2 窗口和 OpenGL 上下文
 */
class WindowSvc : public IService {
public:
  /**
   * @brief 获取单例实例
   */
  static WindowSvc &inst();

  const char *name() const override { return "WindowSvc"; }
  int pri() const override { return Pri::System; }

  bool init() override;
  void shutdown() override;

  /**
   * @brief 使用配置创建窗口
   */
  bool create(const WindowCfg &cfg);

  /**
   * @brief 处理窗口事件
   * @return true 继续运行，false 应退出
   */
  bool pollEvents();

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

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

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

  /**
   * @brief 获取窗口尺寸
   */
  Size getSize() const;

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

  /**
   * @brief 设置窗口尺寸
   */
  void setSize(int32 w, int32 h);

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

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

  /**
   * @brief 检查是否全屏
   */
  bool isFullscreen() const;

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

  /**
   * @brief 检查是否垂直同步
   */
  bool isVsync() const;

  /**
   * @brief 显示/隐藏窗口
   */
  void setVisible(bool visible);

  /**
   * @brief 检查窗口是否可见
   */
  bool isVisible() const;

  /**
   * @brief 设置窗口关闭回调
   */
  void setOnClose(CloseCb cb) { onClose_ = std::move(cb); }

  /**
   * @brief 设置窗口大小改变回调
   */
  void setOnResize(ResizeCb cb) { onResize_ = std::move(cb); }

  /**
   * @brief 请求关闭窗口
   */
  void requestClose() { shouldClose_ = true; }

  /**
   * @brief 检查是否应该关闭
   */
  bool shouldClose() const { return shouldClose_; }

private:
  WindowSvc() = default;

  SDL_Window *window_ = nullptr;
  SDL_GLContext glCtx_ = nullptr;
  bool shouldClose_ = false;
  bool vsync_ = true;

  CloseCb onClose_;
  ResizeCb onResize_;
};

#define WINDOW extra2d::WindowSvc::inst()

} // namespace extra2d
