#pragma once

#include <frostbite2D/graphics/batch.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/graphics/render_resolution.h>
#include <frostbite2D/graphics/render_style.h>
#include <frostbite2D/graphics/shader.h>
#include <frostbite2D/graphics/shader_manager.h>
#include <frostbite2D/graphics/texture.h>
#include <frostbite2D/graphics/types.h>
#include <string>
#include <vector>

namespace frostbite2D {

class RenderTexture;

class Renderer {
public:
  static Renderer& get();

  bool init();
  void shutdown();

  void beginFrame();
  void endFrame();
  void flush();
  bool beginRenderToTexture(RenderTexture& target, Camera* camera,
                            const Color& clearColor = Color(0.0f, 0.0f, 0.0f, 0.0f),
                            bool clear = true);
  bool endRenderToTexture();

  void setViewport(int x, int y, int width, int height);
  void setWindowSize(int width, int height, float contentScaleX = 1.0f,
                     float contentScaleY = 1.0f);
  void setVirtualResolutionEnabled(bool enabled);
  void setVirtualResolution(int width, int height);
  void setResolutionScaleMode(ResolutionScaleMode mode);
  void setSeparateUIVirtualResolutionEnabled(bool enabled);
  void setUIVirtualResolution(int width, int height);
  void setUIResolutionScaleMode(ResolutionScaleMode mode);
  void setClearColor(float r, float g, float b, float a = 1.0f);
  void setClearColor(const Color& color);
  void clear(uint32_t flags);
  /**
   * @brief 设置应用默认渲染风格预设
   */
  void setDefaultRenderStyleProfile(RenderStyleProfileId profile);
  /**
   * @brief 获取应用默认渲染风格预设
   */
  RenderStyleProfileId getDefaultRenderStyleProfile() const {
    return defaultRenderStyleProfile_;
  }
  /**
   * @brief 切换当前正在使用的渲染风格上下文
   */
  void setActiveRenderStyleProfile(RenderStyleProfileId profile,
                                   RenderStyleLayerRole role);
  /**
   * @brief 将指定风格作用到某个相机
   */
  void applyRenderStyleToCamera(Camera* camera, RenderStyleProfileId profile,
                                RenderStyleLayerRole role) const;

  void setCamera(Camera* camera);
  Camera* getCamera() { return camera_; }
  int getVirtualWidth() const;
  int getVirtualHeight() const;
  int getUIVirtualWidth() const;
  int getUIVirtualHeight() const;
  Rect getViewportRect() const;
  Rect getUIViewportRect() const;
  const RenderResolutionState& getResolutionState() const {
    return resolutionState_;
  }
  const RenderResolutionState& getUIResolutionState() const {
    return uiResolutionState_;
  }
  bool isInitialized() const { return initialized_; }
  bool isFrameActive() const { return frameActive_; }
  bool isRenderingToTexture() const { return !renderTargetStack_.empty(); }
  void setCullingEnabled(bool enabled) { cullingEnabled_ = enabled; }
  bool isCullingEnabled() const { return cullingEnabled_; }
  void applyWorldViewport() const;
  void applyUIViewport() const;
  Vec2 screenToVirtual(const Vec2& screenPos) const;
  Vec2 screenToUIVirtual(const Vec2& screenPos) const;
  Vec2 virtualToScreen(const Vec2& virtualPos) const;

  void drawQuad(const Vec2& pos, const Size& size, float cr = 1.0f,
                float cg = 1.0f, float cb = 1.0f, float ca = 1.0f);
  void drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture);
  void drawQuad(const Rect& rect, const Color& color);

  void drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture);
  void drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize,
                  Ptr<Texture> texture,
                  const Color& color = Color(1, 1, 1, 1));
  void setupBlendMode(BlendMode mode);
  /**
   * @brief 获取当前激活的层级风格设置
   */
  const RenderStyleLayerSettings& getActiveRenderStyle() const {
    return activeRenderStyle_;
  }
  /**
   * @brief 当前风格是否要求顶点像素对齐
   */
  bool shouldSnapVertices() const { return activeRenderStyle_.vertexPixelSnap; }
  /**
   * @brief 当前风格是否优先使用像素风采样
   */
  bool shouldUsePixelArtSampling() const {
    return activeRenderStyle_.pixelArtSampling;
  }
  /**
   * @brief 当前风格是否需要对子纹理 UV 做向内收缩
   */
  bool shouldShrinkSubTextureUVs() const {
    return activeRenderStyle_.shrinkSubTextureUVs;
  }

  ShaderManager& getShaderManager() { return shaderManager_; }
  Batch& getBatch() { return batch_; }

private:
  Renderer();

  void updateUniforms();
  void recalculateResolutionState();
  void recalculateSingleResolutionState(RenderResolutionState& state,
                                        bool useVirtualResolution,
                                        int virtualWidth, int virtualHeight,
                                        ResolutionScaleMode mode) const;
  void syncCameraViewport();

  struct RenderTargetState {
    uint32 framebuffer = 0;
    int viewportX = 0;
    int viewportY = 0;
    int viewportWidth = 1;
    int viewportHeight = 1;
    float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
    Camera* camera = nullptr;
    bool startedStandaloneBatch = false;
    bool cullingEnabled = true;
  };

  ShaderManager shaderManager_;
  Batch batch_;
  Camera* camera_ = nullptr;
  RenderStyleProfileId defaultRenderStyleProfile_ = RenderStyleProfileId::Hybrid2D;
  RenderStyleProfileId activeRenderStyleProfile_ = RenderStyleProfileId::Hybrid2D;
  RenderStyleLayerRole activeRenderStyleRole_ = RenderStyleLayerRole::World;
  RenderStyleLayerSettings activeRenderStyle_;

  uint32_t clearColor_[4] = {0, 0, 0, 255};
  bool useVirtualResolution_ = false;
  int virtualWidth_ = 1280;
  int virtualHeight_ = 720;
  ResolutionScaleMode resolutionMode_ = ResolutionScaleMode::Fit;
  bool useSeparateUIVirtualResolution_ = false;
  int uiVirtualWidth_ = 0;
  int uiVirtualHeight_ = 0;
  ResolutionScaleMode uiResolutionMode_ = ResolutionScaleMode::Fit;
  RenderResolutionState resolutionState_;
  RenderResolutionState uiResolutionState_;

  bool initialized_ = false;
  bool frameActive_ = false;
  bool cullingEnabled_ = true;
  std::vector<RenderTargetState> renderTargetStack_;

  Renderer(const Renderer&) = delete;
  Renderer& operator=(const Renderer&) = delete;
};

} // namespace frostbite2D
