#pragma once

#include "character/CharacterActionLibrary.h"
#include "character/CharacterAnimation.h"
#include "character/CharacterDataLoader.h"
#include "character/CharacterEquipmentManager.h"
#include "character/CharacterInputRouter.h"
#include "character/CharacterShadowActor.h"
#include "character/CharacterStateMachine.h"
#include <frostbite2D/2d/actor.h>
#include <frostbite2D/event/event.h>
#include <frostbite2D/event/joystick_event.h>
#include <frostbite2D/event/key_event.h>
#include <optional>
#include <string>

namespace frostbite2D {

class GameMap;

/// @brief 角色系统的主聚合对象。
///
/// 这个类可以理解为“角色外壳”：
/// - 输入事件先进入 `OnEvent()`，再由 `CharacterInputRouter` 转成统一命令
/// - `OnUpdate()` 把命令整理成意图，交给 `CharacterStateMachine` 决策
/// - `CharacterMotor` 负责推进逻辑世界坐标
/// - 最后通过 `Actor` 和 `CharacterAnimation` 把结果表现到屏幕上
///
/// 所以阅读这个类时，可以重点抓住两条主线：
/// 1. 数据如何从输入流到状态机
/// 2. 状态机如何把逻辑结果投影成最终动画和位置
class CharacterObject : public Actor {
public:
  CharacterObject() = default;
  ~CharacterObject() override;

  /// @brief 二段初始化角色。
  /// @param jobId 职业 id，用来加载职业配置、动作定义和动画资源。
  /// @return 初始化成功返回 true。
  bool Construction(int jobId);

  // ---------------------------------------------------------------------------
  // 表现与外部驱动入口
  // ---------------------------------------------------------------------------

  /// @brief 直接切换当前播放的资源动作标签。
  ///
  /// 这里操作的是“动画表现层名字”，不一定等于逻辑动作 id。
  void SetAction(const std::string& actionName);

  /// @brief 设置朝向，并同步到动画镜像。
  /// @param direction 大于等于 0 视为朝右，小于 0 视为朝左。
  void SetDirection(int direction);

  /// @brief 只改地面平面上的 x/y，再重新投影到屏幕。
  void SetCharacterPosition(const Vec2& pos);

  /// @brief 写入逻辑世界坐标，并把它转换成屏幕坐标和遮挡顺序。
  void SetWorldPosition(const CharacterWorldPosition& pos);

  /// @brief 向输入缓冲区手动压入一条命令。
  ///
  /// 一般用于 AI、脚本或测试代码模拟输入，而不是直接发 SDL 事件。
  void PushCommand(const CharacterCommand& command);

  /// @brief 处理一次受击请求。
  ///
  /// 这里会先检查无敌、霸体、当前动作是否允许被打断，再决定是否强制切到受击状态。
  void ApplyHit(const HitContext& hit);

  /// @brief 开关输入处理。
  ///
  /// 关闭后角色仍会继续更新状态和运动，只是不再消费外部输入事件。
  void SetInputEnabled(bool enabled) { inputEnabled_ = enabled; }
  bool IsInputEnabled() const { return inputEnabled_; }

  /// @brief 角色每帧主循环。
  ///
  /// 顺序固定为：命令缓冲推进 -> 采样实时输入 -> 生成意图 -> 状态机更新
  /// -> motor 推进 -> 投影到 Actor 坐标。
  void Update(float deltaTime) override;
  void OnUpdate(float deltaTime) override;
  void OnAdded(Actor* parent) override;
  void PrepareRenderFrame();

  /// @brief 统一输入入口。
  ///
  /// `Actor` 底层会把不同 SDL 事件派发到这里；本类再把它们转交给 `CharacterInputRouter`。
  bool OnEvent(const Event& event) override;

  // ---------------------------------------------------------------------------
  // 运行时查询接口
  // ---------------------------------------------------------------------------

  int GetJobId() const { return jobId_; }
  int GetGrowType() const { return growType_; }
  int GetDirection() const { return direction_; }
  const std::string& GetCurrentAction() const { return currentAction_; }
  CharacterStateId GetState() const { return stateMachine_.GetState(); }
  const CharacterIntent& GetCurrentIntent() const { return currentIntent_; }
  const CharacterWorldPosition& GetWorldPosition() const { return motor_.position; }
  const CharacterMotor& GetMotor() const { return motor_; }
  CharacterMotor& GetMotorMutable() { return motor_; }
  CharacterCommandBuffer& GetCommandBufferMutable() { return commandBuffer_; }
  float GetLastDeltaTime() const { return lastDeltaTime_; }
  const CharacterRuntimeBlackboard& GetRuntimeBlackboard() const { return runtimeBlackboard_; }
  CharacterRuntimeBlackboard& GetRuntimeBlackboardMutable() { return runtimeBlackboard_; }

  /// @brief Prepare one-shot data for the next action transition.
  ///
  /// The returned context is consumed by the next successful `EnterAction()`.
  CharacterActionContextData& PreparePendingActionContext(
      const std::string& requestedActionId,
      const std::string& sourceActionId = std::string(),
      CharacterStateId sourceStateId = CharacterStateId::Idle);
  void ClearPendingActionContext();
  bool HasPendingActionContext() const { return pendingActionContext_.valid; }
  const CharacterActionContextData* GetPendingActionContext() const;
  CharacterActionContextData* GetPendingActionContextMutable();

  /// @brief Read transition metadata for the currently running action.
  const CharacterActionContextData* GetCurrentActionContext() const;
  CharacterActionContextData* GetCurrentActionContextMutable();
  bool HasCurrentActionContext() const { return currentActionContext_.valid; }
  void ClearCurrentActionContext();

  /// @brief 按逻辑动作 id 查询动作定义。
  const CharacterActionDefinition* FindAction(const std::string& actionId) const;

  /// @brief 严格查询逻辑动作；不存在时会输出详细错误并请求退出程序。
  const CharacterActionDefinition* RequireAction(const std::string& actionId,
                                                 const char* phase) const;

  /// @brief 播放某个动画标签。
  ///
  /// 当前只是对 `SetAction()` 的语义包装，方便状态机表达“播放动作标签”。
  void PlayAnimationTag(const std::string& actionTag);
  bool HasAnimationTag(const std::string& actionTag) const;

  /// @brief 查询当前动作主动画是否已经播放完成。
  bool IsCurrentAnimationFinished() const;

  /// @brief 读取当前动作主动画的帧信息，方便状态类/脚本做运行时判断。
  int GetCurrentAnimationFrameIndex() const;
  int GetCurrentAnimationFrameCount() const;
  float GetCurrentAnimationProgressNormalized() const;
  animation::AniFrame GetCurrentAnimationFrameInfo() const;
  bool HasCompositeTexture() const;
  Ptr<Texture> GetCompositeTexture() const;
  Vec2 GetCompositeTextureSize() const;
  Vec2 GetCompositeOriginInTexture() const;
  Vec2 GetCompositeGroundAnchorInTexture() const;
  uint64 GetCompositeTextureVersion() const;

  /// @brief 绑定当前动作主动画的运行时回调，供后续脚本系统接入。
  void SetAnimationFrameFlagCallback(CharacterAnimation::ActionFrameFlagCallback callback);
  void SetAnimationEndCallback(CharacterAnimation::ActionEndCallback callback);

  /// @brief 输出角色动作/动画的致命错误，并请求应用退出。
  void ReportFatalCharacterError(const char* phase,
                                 const char* reason,
                                 const std::string& requestedActionId = std::string(),
                                 const std::string& requestedAnimationTag = std::string())
      const;

  /// @brief 触发状态生命周期钩子。
  ///
  /// 当前为空实现，预留给后续脚本系统接管 `on_enter/on_update/on_exit`。
  void RunStateHook(const std::string& phase,
                    CharacterStateId stateId,
                    const CharacterActionDefinition* action);

  /// @brief 同步逻辑朝向到 motor 与动画。
  void SetFacing(int direction);

  const character::CharacterConfig* GetConfig() const {
    return config_ ? &config_.value() : nullptr;
  }
  const CharacterEquipmentManager& GetEquipmentManager() const { return equipmentManager_; }

private:
  void CommitPendingActionContext(const std::string& defaultRequestedActionId,
                                  const std::string& defaultSourceActionId,
                                  CharacterStateId defaultSourceStateId);
  GameMap* FindOwningMap() const;
  void ApplyMapMovementConstraints(const CharacterWorldPosition& previousPosition);
  void QueueMapTransitionIfNeeded();
  void SyncActorPositionFromWorld();
  void SyncShadowAttachment();
  void SyncShadowPresentation();
  void DetachShadowActor();
  bool SetActionStrict(const std::string& actionName,
                       const char* phase,
                       const std::string& requestedActionId);
  std::string DescribeConfiguredAnimationTags() const;

  /// 职业 id，用于加载职业配置、动作表和资源。
  int jobId_ = -1;

  /// 转职/成长阶段，当前项目里先保留这个槽位。
  int growType_ = -1;

  /// 表现层朝向：1 表示右，-1 表示左。
  int direction_ = 1;

  /// 当前正在播放的资源动作标签，不一定等于逻辑 actionId。
  std::string currentAction_;

  /// 角色静态配置，包含职业、动画路径等加载结果。
  std::optional<character::CharacterConfig> config_;

  /// 负责拼装装备部件，决定分层 Avatar 的表现资源。
  CharacterEquipmentManager equipmentManager_;

  /// 动作定义表：保存显式注册的逻辑动作入口。
  CharacterActionLibrary actionLibrary_;

  /// 输入适配层，把键盘/手柄事件收敛成统一命令。
  CharacterInputRouter inputRouter_;

  /// 输入缓冲区，支持预输入和连段窗口。
  CharacterCommandBuffer commandBuffer_;

  /// 当前帧从命令缓冲整理出的“角色意图”。
  CharacterIntent currentIntent_;

  /// Character-wide shared runtime data for skills, buffs, and future scripts.
  CharacterRuntimeBlackboard runtimeBlackboard_;

  /// One-shot payload prepared before switching into the next action.
  CharacterActionContextData pendingActionContext_;

  /// Metadata attached to the action currently running inside Action state.
  CharacterActionContextData currentActionContext_;

  /// 状态调度器，负责状态切换与动作进入。
  CharacterStateMachine stateMachine_;

  /// 纯运动数据：位置、速度、落地状态和朝向都在这里维护。
  CharacterMotor motor_;

  /// 战斗附加状态，如霸体、无敌、控制锁定。
  CharacterStatus status_;

  /// 真正负责播放角色分层动画的 Actor 子节点。
  RefPtr<CharacterAnimation> animationManager_ = nullptr;

  /// ???? normal ???????????
  RefPtr<CharacterShadowActor> shadowActor_ = nullptr;
  GameMap* shadowAttachedMap_ = nullptr;

  /// 缓存上一帧 deltaTime，方便状态和脚本系统查询。
  float lastDeltaTime_ = 0.0f;

  /// 是否允许从事件系统接收输入；AI/剧情接管时可临时关闭。
  bool inputEnabled_ = true;

  friend class CharacterStateMachine;
};

} // namespace frostbite2D
