#pragma once

#include <frostbite2D/types/type_alias.h>
#include <frostbite2D/resource/pvf_archive.h>
#include <optional>
#include <string>
#include <vector>
#include <cstring>

namespace frostbite2D {

/**
 * @brief 脚本指令操作码枚举
 */
enum class ScriptOpcode : uint8 {
  Integer = 2,            ///< 整数值
  Float = 4,              ///< 浮点值
  StringRef5 = 5,         ///< 二进制字符串引用（类型5）
  StringRef6 = 6,         ///< 二进制字符串引用（类型6）
  StringRef7 = 7,         ///< 二进制字符串引用（类型7）
  StringRef8 = 8,         ///< 二进制字符串引用（类型8）
  ExtendedString9 = 9,    ///< 扩展字符串（带额外字节）
  ExtendedString10 = 10,  ///< 扩展字符串
};

/**
 * @brief 脚本值类型
 */
enum class ScriptValueType {
  Empty,    ///< 空值
  Integer,  ///< 整数值
  Float,    ///< 浮点值
  String,   ///< 字符串值
};

/**
 * @brief 脚本解析结果值
 */
struct ScriptValue {
  ScriptValueType type = ScriptValueType::Empty;  ///< 值类型
  int32 intValue = 0;                              ///< 整数值（type == Integer 时有效）
  double floatValue = 0.0;                         ///< 浮点值（type == Float 时有效）
  std::string stringValue;                          ///< 字符串值（type == String 时有效）

  /**
   * @brief 判断是否为空值
   */
  bool isEmpty() const { return type == ScriptValueType::Empty; }

  /**
   * @brief 转换为字符串表示
   */
  std::string toString() const;
};

/**
 * @brief 脚本二进制数据解析器
 *
 * 用于解析 PVF 存档中的脚本二进制数据。
 * 每条指令为 5 字节：1 字节操作码 + 4 字节数据。
 * 支持与 PvfArchive 交互获取字符串资源。
 *
 * @example
 * auto& archive = PvfArchive::get();
 * if (auto rawData = archive.getFileRawData("script/example.bin")) {
 *   ScriptParser parser(*rawData, "script/example.bin");
 *   
 *   // 迭代解析
 *   while (!parser.isEnd()) {
 *     if (auto value = parser.next()) {
 *       // 处理 value
 *     }
 *   }
 *   
 *   // 或者一次性解析所有
 *   auto allValues = parser.parseAll();
 * }
 */
class ScriptParser {
public:
  /**
   * @brief 从 RawData 构造
   * @param data 原始数据
   * @param filePath 文件路径（用于提取文件类型）
   */
  ScriptParser(const RawData& data, const std::string& filePath);

  /**
   * @brief 从字节数组构造
   * @param data 字节数组
   * @param filePath 文件路径（用于提取文件类型）
   */
  ScriptParser(const std::vector<uint8>& data, const std::string& filePath);

  /**
   * @brief 从指针和大小构造
   * @param data 数据指针
   * @param size 数据大小
   * @param filePath 文件路径（用于提取文件类型）
   */
  ScriptParser(const char* data, size_t size, const std::string& filePath);

  // ---------------------------------------------------------------------------
  // 迭代器风格 API
  // ---------------------------------------------------------------------------

  /**
   * @brief 获取下一个值
   * @return 解析的值，失败或结束返回 std::nullopt
   */
  std::optional<ScriptValue> next();

  /**
   * @brief 回退一个指令
   */
  void back();

  /**
   * @brief 检查是否已到达数据末尾
   * @return 到达末尾返回 true
   */
  bool isEnd() const;

  /**
   * @brief 重置解析位置到开头
   */
  void reset();

  // ---------------------------------------------------------------------------
  // 批量解析
  // ---------------------------------------------------------------------------

  /**
   * @brief 解析所有值
   * @return 所有解析值的列表
   */
  std::vector<ScriptValue> parseAll();

  // ---------------------------------------------------------------------------
  // 状态查询
  // ---------------------------------------------------------------------------

  /**
   * @brief 获取当前解析位置
   * @return 当前位置（字节偏移）
   */
  size_t position() const;

  /**
   * @brief 获取数据总大小
   * @return 数据大小（字节）
   */
  size_t size() const;

  /**
   * @brief 获取文件路径
   * @return 文件路径
   */
  const std::string& filePath() const;

  /**
   * @brief 获取文件类型（从路径提取）
   * @return 文件类型
   */
  const std::string& fileType() const;

  /**
   * @brief 检查解析器是否有效（有数据）
   * @return 有效返回 true
   */
  bool isValid() const;

private:
  /**
   * @brief 从文件路径提取文件类型
   * @param filePath 文件路径
   * @return 文件类型
   */
  std::string extractFileType(const std::string& filePath) const;

  /**
   * @brief 读取 1 字节
   * @param offset 偏移位置
   * @return 字节值
   */
  uint8 readByte(size_t offset) const;

  /**
   * @brief 读取 4 字节整数
   * @param offset 偏移位置
   * @return 整数值
   */
  int32 readInt32(size_t offset) const;

  /**
   * @brief 解析单个值
   * @param offset 偏移位置
   * @return 解析的值
   */
  std::optional<ScriptValue> parseValueAt(size_t offset) const;

  std::vector<char> data_;       ///< 数据副本
  size_t position_ = 2;           ///< 当前解析位置（从第 2 字节开始）
  std::string filePath_;           ///< 文件路径
  std::string fileType_;           ///< 文件类型
};

} // namespace frostbite2D
