#pragma once

#include <extra2d/core/types.h>
#include <extra2d/scene/scene.h>

#include <functional>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>

namespace extra2d {

struct RenderCommand;
class TransitionScene;
enum class TransitionType;

/**
 * @brief 场景管理器 - 管理场景的生命周期和切换
 */
class SceneManager {
public:
  using TransitionCallback = std::function<void()>;

  static SceneManager &get();

  // ------------------------------------------------------------------------
  // 基本场景操作（无过渡效果）
  // ------------------------------------------------------------------------
  void runWithScene(Ptr<Scene> scene);
  void replaceScene(Ptr<Scene> scene);
  void pushScene(Ptr<Scene> scene);
  void popScene();
  void popToRootScene();
  void popToScene(const std::string &name);

  // ------------------------------------------------------------------------
  // 带过渡效果的场景操作
  // ------------------------------------------------------------------------

  /**
   * @brief 替换当前场景（带过渡效果）
   * @param scene 新场景
   * @param transition 过渡类型
   * @param duration 过渡持续时间（秒）
   */
  void replaceScene(Ptr<Scene> scene, TransitionType transition,
                    float duration = 0.5f);

  /**
   * @brief 压入新场景（带过渡效果）
   * @param scene 新场景
   * @param transition 过渡类型
   * @param duration 过渡持续时间（秒）
   */
  void pushScene(Ptr<Scene> scene, TransitionType transition,
                 float duration = 0.5f);

  /**
   * @brief 弹出当前场景（带过渡效果）
   * @param transition 过渡类型
   * @param duration 过渡持续时间（秒）
   */
  void popScene(TransitionType transition, float duration = 0.5f);

  /**
   * @brief 弹出到根场景（带过渡效果）
   * @param transition 过渡类型
   * @param duration 过渡持续时间（秒）
   */
  void popToRootScene(TransitionType transition, float duration = 0.5f);

  /**
   * @brief 弹出到指定场景（带过渡效果）
   * @param name 目标场景名称
   * @param transition 过渡类型
   * @param duration 过渡持续时间（秒）
   */
  void popToScene(const std::string &name, TransitionType transition,
                  float duration = 0.5f);

  /**
   * @brief 使用自定义过渡场景进入场景
   * @param scene 新场景
   * @param transitionScene 过渡场景
   */
  void enterScene(Ptr<Scene> scene, Ptr<TransitionScene> transitionScene);

  // ------------------------------------------------------------------------
  // 场景查询
  // ------------------------------------------------------------------------
  Ptr<Scene> getCurrentScene() const;
  Ptr<Scene> getPreviousScene() const;
  Ptr<Scene> getRootScene() const;
  Ptr<Scene> getSceneByName(const std::string &name) const;

  size_t getSceneCount() const { return sceneStack_.size(); }
  bool isEmpty() const { return sceneStack_.empty(); }
  bool hasScene(const std::string &name) const;

  // ------------------------------------------------------------------------
  // 更新和渲染
  // ------------------------------------------------------------------------
  void update(float dt);
  void render(RenderBackend &renderer);
  void collectRenderCommands(std::vector<RenderCommand> &commands);

  // ------------------------------------------------------------------------
  // 过渡状态
  // ------------------------------------------------------------------------
  bool isTransitioning() const { return isTransitioning_; }
  void setTransitionCallback(TransitionCallback callback) {
    transitionCallback_ = callback;
  }

  void end();
  void purgeCachedScenes();

public:
  SceneManager() = default;
  ~SceneManager() = default;
  SceneManager(const SceneManager &) = delete;
  SceneManager &operator=(const SceneManager &) = delete;

  void enterScene(Ptr<Scene> scene);

private:
  /**
   * @brief 启动过渡
   * @param from 源场景
   * @param to 目标场景
   * @param type 过渡类型
   * @param duration 过渡持续时间
   * @param stackAction 过渡完成后的栈操作
   */
  void startTransition(Ptr<Scene> from, Ptr<Scene> to, TransitionType type,
                       float duration, std::function<void()> stackAction);

  /**
   * @brief 创建过渡场景
   * @param type 过渡类型
   * @param duration 过渡持续时间
   * @param inScene 目标场景
   * @return 过渡场景智能指针
   */
  Ptr<TransitionScene> createTransitionScene(TransitionType type, float duration,
                                             Ptr<Scene> inScene);

  /**
   * @brief 完成过渡
   */
  void finishTransition();

  void doSceneSwitch();
  void dispatchPointerEvents(Scene &scene);

  std::stack<Ptr<Scene>> sceneStack_;
  std::unordered_map<std::string, Ptr<Scene>> namedScenes_;

  bool isTransitioning_ = false;
  TransitionCallback transitionCallback_;

  Ptr<Scene> nextScene_;
  bool sendCleanupToScene_ = false;

  Ptr<TransitionScene> activeTransitionScene_;
  std::function<void()> transitionStackAction_;

  Node *hoverTarget_ = nullptr;
  Node *captureTarget_ = nullptr;
  Vec2 lastPointerWorld_ = Vec2::Zero();
  bool hasLastPointerWorld_ = false;
};

} // namespace extra2d
