#pragma once

#include <frostbite2D/types/type_alias.h>
#include <optional>
#include <random>
#include <string>
#include <unordered_map>
#include <vector>

namespace frostbite2D {

/**
 * @brief 音频项类型枚举
 */
enum class AudioEntryType {
  None,    ///< 无效
  Effect,  ///< 音效
  Music,   ///< 背景音乐
  Random   ///< 随机音效组
};

/**
 * @brief 音效配置
 */
struct AudioEffect {
  std::string id;           ///< 音效 ID
  std::string file;         ///< 文件路径
  std::string subgroup;     ///< 子组（可选）
  int32 loopDelay = -1;     ///< 循环延迟（-1 表示未设置）
  int32 loopDelayRange = -1;///< 循环延迟范围（-1 表示未设置）
};

/**
 * @brief 音乐配置
 */
struct AudioMusic {
  std::string id;           ///< 音乐 ID
  std::string file;         ///< 文件路径
  int32 loopDelay = -1;     ///< 循环延迟（-1 表示未设置）
};

/**
 * @brief 随机音效项
 */
struct RandomItem {
  std::string tag;          ///< 音效标签（ID）
  int32 probability = 0;    ///< 概率权重
};

/**
 * @brief 随机音效组
 */
struct AudioRandom {
  std::string id;                       ///< 随机组 ID
  std::vector<RandomItem> items;       ///< 随机项列表
};

/**
 * @brief 统一的音频条目（包含类型和数据）
 */
struct AudioEntry {
  AudioEntryType type = AudioEntryType::None;  ///< 条目类型

  const AudioEffect* effect = nullptr;  ///< 音效指针（type == Effect 时有效）
  const AudioMusic* music = nullptr;    ///< 音乐指针（type == Music 时有效）
  const AudioRandom* random = nullptr;  ///< 随机组指针（type == Random 时有效）

  /// @brief 判断是否有效
  bool isValid() const { return type != AudioEntryType::None; }

  /// @brief 判断是否为音效
  bool isEffect() const { return type == AudioEntryType::Effect; }

  /// @brief 判断是否为音乐
  bool isMusic() const { return type == AudioEntryType::Music; }

  /// @brief 判断是否为随机组
  bool isRandom() const { return type == AudioEntryType::Random; }

  /// @brief 安全获取文件路径
  std::string getFilePath() const {
    if (type == AudioEntryType::Effect && effect)
      return effect->file;
    if (type == AudioEntryType::Music && music)
      return music->file;
    return "";
  }

  /// @brief 安全获取子组
  std::string getSubgroup() const {
    if (type == AudioEntryType::Effect && effect)
      return effect->subgroup;
    return "";
  }
};

/**
 * @brief 音频数据库（单例）
 *
 * 用于解析和访问 audio.xml 文件中的音频配置。
 * 提供统一的查询接口，自动判断音频类型。
 *
 * @example
 * auto& audioDB = AudioDatabase::get();
 * if (audioDB.loadFromFile("audio.xml")) {
 *   // 统一查询
 *   if (auto entry = audioDB.get("GN_FINAL_SHOT_01")) {
 *     // 使用 entry
 *   }
 *   
 *   // 获取文件路径
 *   if (auto filePath = audioDB.getFilePath("GN_FINAL_SHOT_01")) {
 *     // 使用 *filePath
 *   }
 *   
 *   // 获取音效（自动处理随机组）
 *   if (auto soundId = audioDB.getSound("R_GN_FINAL_SHOT")) {
 *     // 使用 *soundId
 *   }
 * }
 */
class AudioDatabase {
public:
  /**
   * @brief 获取单例实例
   * @return 音频数据库实例引用
   */
  static AudioDatabase& get();

  AudioDatabase(const AudioDatabase&) = delete;
  AudioDatabase& operator=(const AudioDatabase&) = delete;

  // ---------------------------------------------------------------------------
  // 加载和解析
  // ---------------------------------------------------------------------------

  /**
   * @brief 从文件加载音频数据库
   * @param path XML 文件路径
   * @return 加载成功返回 true
   */
  bool loadFromFile(const std::string& path);

  /**
   * @brief 从字符串加载音频数据库
   * @param xmlContent XML 内容字符串
   * @return 加载成功返回 true
   */
  bool loadFromString(const std::string& xmlContent);

  /**
   * @brief 清空数据库
   */
  void clear();

  /**
   * @brief 检查数据库是否已加载
   * @return 已加载返回 true
   */
  bool isLoaded() const;

  // ---------------------------------------------------------------------------
  // 统一查询接口
  // ---------------------------------------------------------------------------

  /**
   * @brief 统一查询：输入任意 ID，自动判断类型
   * @param id 音频 ID（可以是 EFFECT、MUSIC 或 RANDOM 的 ID）
   * @return 音频条目，未找到返回 std::nullopt
   */
  std::optional<AudioEntry> get(const std::string& id);

  /**
   * @brief 获取音效 ID（自动处理 RANDOM 类型）
   *
   * 如果 id 是 RANDOM 类型，会按概率随机选择一个音效；
   * 如果 id 是 EFFECT 类型，直接返回该 ID。
   *
   * @param id 音效 ID 或随机组 ID
   * @return 音效 ID，未找到返回 std::nullopt
   */
  std::optional<std::string> getSound(const std::string& id);

  /**
   * @brief 获取文件路径
   *
   * 对于 EFFECT 和 MUSIC 类型，返回对应的文件路径；
   * 对于 RANDOM 类型，先随机选择一个音效再返回其文件路径。
   *
   * @param id 音频 ID
   * @return 文件路径，未找到返回 std::nullopt
   */
  std::optional<std::string> getFilePath(const std::string& id);

  // ---------------------------------------------------------------------------
  // 类型特定查询（高级用法）
  // ---------------------------------------------------------------------------

  /**
   * @brief 获取音效配置
   * @param id 音效 ID
   * @return 音效配置指针，未找到返回 std::nullopt
   */
  std::optional<const AudioEffect*> getEffect(const std::string& id);

  /**
   * @brief 获取音乐配置
   * @param id 音乐 ID
   * @return 音乐配置指针，未找到返回 std::nullopt
   */
  std::optional<const AudioMusic*> getMusic(const std::string& id);

  /**
   * @brief 获取随机音效组配置
   * @param id 随机组 ID
   * @return 随机组配置指针，未找到返回 std::nullopt
   */
  std::optional<const AudioRandom*> getRandom(const std::string& id);

  // ---------------------------------------------------------------------------
  // 统计信息
  // ---------------------------------------------------------------------------

  /**
   * @brief 获取音效数量
   */
  size_t effectCount() const;

  /**
   * @brief 获取音乐数量
   */
  size_t musicCount() const;

  /**
   * @brief 获取随机组数量
   */
  size_t randomCount() const;

  // ---------------------------------------------------------------------------
  // 便捷访问方法（推荐使用）
  // ---------------------------------------------------------------------------

  /**
   * @brief 检查 ID 是否存在
   * @param id 音频 ID
   * @return 存在返回 true
   */
  bool has(const std::string& id);

  /**
   * @brief 获取文件路径（不存在返回空字符串）
   * @param id 音频 ID
   * @return 文件路径，未找到返回空字符串
   */
  std::string filePath(const std::string& id);

  /**
   * @brief 获取音效 ID（自动处理随机组，不存在返回空字符串）
   * @param idOrRandomId 音效 ID 或随机组 ID
   * @return 音效 ID，未找到返回空字符串
   */
  std::string soundId(const std::string& idOrRandomId);

  /**
   * @brief 获取子组（EFFECT 的 SUBGROUP 属性）
   * @param id 音频 ID
   * @return 子组名，未找到或不存在返回空字符串
   */
  std::string subgroup(const std::string& id);

  /**
   * @brief 获取条目类型
   * @param id 音频 ID
   * @return 条目类型，未找到返回 AudioEntryType::None
   */
  AudioEntryType typeOf(const std::string& id);

  // ---------------------------------------------------------------------------
  // 带检查的访问方法
  // ---------------------------------------------------------------------------

  /**
   * @brief 尝试获取文件路径，带成功标志
   * @param id 音频 ID
   * @param outPath 输出文件路径
   * @return 成功返回 true
   */
  bool tryGetFilePath(const std::string& id, std::string& outPath);

  /**
   * @brief 尝试获取音效 ID，带成功标志
   * @param id 音效 ID 或随机组 ID
   * @param outSoundId 输出音效 ID
   * @return 成功返回 true
   */
  bool tryGetSoundId(const std::string& id, std::string& outSoundId);

private:
  AudioDatabase() = default;
  ~AudioDatabase() = default;

  /**
   * @brief 初始化随机数生成器
   */
  void initializeRNG();

  /**
   * @brief 从随机组中按概率选择一个音效
   * @param randomGroup 随机组配置
   * @return 选中的音效 ID
   */
  std::string selectFromRandom(const AudioRandom& randomGroup);

  std::unordered_map<std::string, AudioEffect> effectMap_;   ///< 音效映射
  std::unordered_map<std::string, AudioMusic> musicMap_;     ///< 音乐映射
  std::unordered_map<std::string, AudioRandom> randomMap_;   ///< 随机组映射

  std::mt19937 rng_;            ///< 随机数生成器
  bool rngInitialized_ = false;  ///< 随机数生成器是否已初始化
  bool loaded_ = false;
};

} // namespace frostbite2D
