#pragma once

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

namespace frostbite2D {

enum class CursorType {
  Arrow,
  TextInput,
  Hand,
  SizeAll,
  SizeWE,
  SizeNS,
  SizeNESW,
  SizeNWSE,
  No,
};

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) {}
};

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;

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

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;

  virtual bool create(const WindowConfig& cfg);
  virtual void destroy();
  virtual void poll();
  virtual void swap();
  virtual void close();
  virtual void setTitle(const std::string& title);
  virtual void setSize(int w, int h);
  virtual void setPos(int x, int y);
  virtual void setFullscreen(bool fs);
  virtual void setVSync(bool vsync);
  virtual void setVisible(bool visible);

  virtual int width() const;
  virtual int height() const;
  virtual int drawableWidth() const;
  virtual int drawableHeight() const;
  virtual Size size() const;
  virtual Vec2 pos() const;
  virtual bool fullscreen() const;
  virtual bool vsync() const;
  virtual bool focused() const;
  virtual bool minimized() const;
  virtual void setImmEnabled(bool enabled);
  virtual bool isImmEnabled() const;
  virtual float scaleX() const;
  virtual float scaleY() const;
  virtual bool refreshMetrics(bool emitResize = false);
  virtual void setCursor(CursorType cursor);
  virtual void showCursor(bool show);
  virtual void lockCursor(bool lock);

  using ResizeCb = std::function<void(int, int)>;
  using CloseCb = std::function<void()>;
  using FocusCb = std::function<void(bool)>;

  virtual void onResize(ResizeCb cb);
  virtual void onClose(CloseCb cb);
  virtual void onFocus(FocusCb cb);
  virtual void* native() const;

  SDL_Window* sdlWindow() const { return sdlWindow_; }
  SDL_GLContext glContext() const { return glContext_; }

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

  int width_ = 1280;
  int height_ = 720;
  int drawableWidth_ = 1280;
  int drawableHeight_ = 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;
  bool immEnabled_ = false;
  bool immDisabledByApp_ = false;
  void* immRestoreContext_ = nullptr;

  ResizeCb resizeCb_;
  CloseCb closeCb_;
  FocusCb focusCb_;
};

} // namespace frostbite2D
