#pragma once

#include <frostbite2D/types/type_alias.h>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>

namespace frostbite2D {

/**
 * @brief 二进制文件读取器
 *
 * 将整个二进制文件加载到内存中，提供便捷的读取接口。
 * 支持各种基本类型的读取、定位操作和 CRC 解码。
 *
 * @example
 * BinaryReader reader("data.bin");
 * if (reader.isOpen()) {
 *   int32 value = reader.read<int32>();
 *   std::string str = reader.readString(10);
 * }
 */
class BinaryReader {
public:
  /**
   * @brief 默认构造函数
   */
  BinaryReader() = default;

  /**
   * @brief 从文件构造
   * @param filePath 文件路径
   */
  explicit BinaryReader(const std::string& filePath);

  /**
   * @brief 从内存数据构造
   * @param data 数据指针
   * @param size 数据大小
   */
  BinaryReader(const char* data, size_t size);

  /**
   * @brief 析构函数
   */
  ~BinaryReader() = default;

  // ---------------------------------------------------------------------------
  // 文件操作
  // ---------------------------------------------------------------------------

  /**
   * @brief 打开文件
   * @param filePath 文件路径
   * @return 打开成功返回 true
   */
  bool open(const std::string& filePath);

  /**
   * @brief 从内存加载数据
   * @param data 数据指针
   * @param size 数据大小
   */
  void loadFromMemory(const char* data, size_t size);

  /**
   * @brief 关闭并清空数据
   */
  void close();

  /**
   * @brief 检查文件是否成功打开
   * @return 已打开返回 true
   */
  bool isOpen() const;

  // ---------------------------------------------------------------------------
  // 位置操作
  // ---------------------------------------------------------------------------

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

  /**
   * @brief 设置读取位置
   * @param pos 目标位置（字节偏移）
   */
  void seek(size_t pos);

  /**
   * @brief 跳过指定字节数
   * @param count 要跳过的字节数
   */
  void skip(size_t count);

  /**
   * @brief 检查是否已到达文件末尾
   * @return 到达末尾返回 true
   */
  bool eof() const;

  // ---------------------------------------------------------------------------
  // 信息获取
  // ---------------------------------------------------------------------------

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

  /**
   * @brief 获取剩余可读取的字节数
   * @return 剩余字节数
   */
  size_t remaining() const;

  /**
   * @brief 获取上一次读取的字节数
   * @return 上次读取的字节数
   */
  size_t lastReadCount() const;

  // ---------------------------------------------------------------------------
  // 原始数据读取
  // ---------------------------------------------------------------------------

  /**
   * @brief 读取原始字节数据
   * @param buffer 输出缓冲区
   * @param size 要读取的字节数
   * @return 实际读取的字节数
   */
  size_t read(char* buffer, size_t size);

  /**
   * @brief 读取原始字节数据到 vector
   * @param size 要读取的字节数
   * @return 读取的数据
   */
  std::vector<uint8> readBytes(size_t size);

  /**
   * @brief 获取数据指针（不移动读取位置）
   * @return 当前位置的数据指针
   */
  const char* data() const;

  /**
   * @brief 获取当前位置的数据指针（不移动读取位置）
   * @return 当前位置的数据指针
   */
  const char* currentData() const;

  // ---------------------------------------------------------------------------
  // 类型化读取（模板方法）
  // ---------------------------------------------------------------------------

  /**
   * @brief 读取指定类型的值
   * @tparam T 要读取的类型
   * @return 读取的值
   */
  template <typename T>
  T read() {
    T value;
    read(reinterpret_cast<char*>(&value), sizeof(T));
    return value;
  }

  /**
   * @brief 读取 int8
   * @return 读取的值
   */
  int8 readInt8();

  /**
   * @brief 读取 int16
   * @return 读取的值
   */
  int16 readInt16();

  /**
   * @brief 读取 int32
   * @return 读取的值
   */
  int32 readInt32();

  /**
   * @brief 读取 int64
   * @return 读取的值
   */
  int64 readInt64();

  /**
   * @brief 读取 uint8
   * @return 读取的值
   */
  uint8 readUInt8();

  /**
   * @brief 读取 uint16
   * @return 读取的值
   */
  uint16 readUInt16();

  /**
   * @brief 读取 uint32
   * @return 读取的值
   */
  uint32 readUInt32();

  /**
   * @brief 读取 uint64
   * @return 读取的值
   */
  uint64 readUInt64();

  /**
   * @brief 读取 float
   * @return 读取的值
   */
  float readFloat();

  /**
   * @brief 读取 double
   * @return 读取的值
   */
  double readDouble();

  // ---------------------------------------------------------------------------
  // 字符串读取
  // ---------------------------------------------------------------------------

  /**
   * @brief 读取指定长度的字符串
   * @param length 字符串长度（字节）
   * @return 读取的字符串
   */
  std::string readString(size_t length);

  /**
   * @brief 读取以 null 结尾的字符串
   * @return 读取的字符串
   */
  std::string readNullTerminatedString();

  // ---------------------------------------------------------------------------
  // CRC 解码
  // ---------------------------------------------------------------------------

  /**
   * @brief CRC 解码
   * @param length 要解码的数据长度（字节）
   * @param crc32 CRC32 值
   */
  void crcDecode(size_t length, uint32 crc32);

private:
  std::vector<char> data_;          ///< 存储的数据
  size_t position_ = 0;              ///< 当前读取位置
  size_t lastReadCount_ = 0;         ///< 上一次读取的字节数
};

} // namespace frostbite2D
