#include "resources.hpp"

#include "util/preferences.hpp"
#include "log.hpp"

#include <algorithm>
#include <format>

using namespace game::resource;
using namespace game::util;

namespace game
{
  Resources::Resources()
  {
    for (int i = 0; i < shader::COUNT; i++)
      shaders[i] = Shader(shader::INFO[i].vertex, shader::INFO[i].fragment);

    characters_refresh();
  }

  void Resources::characters_refresh()
  {
    static constexpr auto CHARACTERS_DIRECTORY = "resources/characters";

    characterPreviews.clear();
    characterSaves.clear();
    characters.clear();

    std::error_code ec{};

    if (!std::filesystem::is_directory(CHARACTERS_DIRECTORY, ec))
    {
      if (ec)
        logger.warning(std::format("Failed to read characters directory: {} ({})", CHARACTERS_DIRECTORY, ec.message()));
      else
        logger.warning(std::format("Characters directory not found: {}", CHARACTERS_DIRECTORY));
      return;
    }

    std::vector<std::filesystem::path> archives{};
    for (auto& entry : std::filesystem::recursive_directory_iterator(CHARACTERS_DIRECTORY, ec))
      if (!ec && entry.is_regular_file(ec) && entry.path().extension() == ".zip") archives.emplace_back(entry.path());

    std::ranges::sort(archives);
    for (auto& path : archives)
    {
      auto& preview = characterPreviews.emplace_back();
      preview.load_archive(path, "character.xml");

      auto& character = characters.emplace_back(path);
      characterSaves.emplace_back(character.save_path_get());
    }

    logger.info(std::format("Refreshed character archives: {}", characters.size()));
  }

  void Resources::volume_set(float vol) { Audio::volume_set(vol); }
  void Resources::audio_mute_set(bool isMuted) { Audio::mute_set(isMuted); }

  resource::xml::Character& Resources::character_get(int index) { return characters.at(index); }

  resource::xml::Schema& Resources::character_preview_get(int index) { return characterPreviews.at(index); }

  int Resources::character_index_get(const std::string& key) const
  {
    for (int i = 0; i < (int)characters.size(); i++)
      if (characters[i].path.stem().string() == key) return i;
    return -1;
  }

  std::string Resources::character_key_get(int index) const { return characters.at(index).path.stem().string(); }

  void Resources::last_character_save(int index)
  {
    if (index < 0 || index >= (int)characters.size()) return;
    if (auto* settingsRoot = settings.root()) settingsRoot->lastCharacter = character_key_get(index);
  }

  void Resources::last_character_clear()
  {
    if (auto* settingsRoot = settings.root()) settingsRoot->lastCharacter.clear();
  }

  void Resources::character_save_set(int index, const resource::xml::Schema& save)
  {
    characterSaves.at(index) = save;
    characters.at(index).save = save;
  }

  void Resources::character_save_clear(int index)
  {
    characterSaves.at(index) = resource::xml::Schema();
    characters.at(index).save = resource::xml::Schema();
  }

  Resources::~Resources() { settings.serialize(preferences::path() / "settings.xml"); }
}
