#include <fmt/core.h>
#include "palette.hpp"
#include "config.hpp"
#include "dbc.hpp"

namespace palette {
  using std::string;
  using nlohmann::json;

  struct PaletteMgr {
    std::unordered_map<string, sf::Color> palettes;
    std::string config;
    std::unordered_map<string, string> pending_refs;
    bool initialized = false;
  };

  static PaletteMgr COLOR;

  void init(const string &json_file) {
    if(!COLOR.initialized) {
      COLOR.initialized = true;

      COLOR.config = json_file;
      Config config(json_file);
      json& colors = config.json();

      for(auto [key, value_specs] : colors.items()) {
        const string& base_key = key;

        for(auto [value, rgba] : value_specs.items()) {
          auto color_path = base_key + ":" + value;
          dbc::check(!COLOR.palettes.contains(color_path),
              fmt::format("PALLETES config {} already has a color path {}", COLOR.config, color_path));

          if(rgba.type() == json::value_t::string) {
            COLOR.pending_refs.try_emplace(color_path, rgba);
          } else {
            uint8_t alpha = rgba.size() == 3 ? 255 : (uint8_t)rgba[3];
            sf::Color color{rgba[0], rgba[1], rgba[2], alpha};
            COLOR.palettes.try_emplace(color_path, color);
          }
        }
      }
    }

    for(auto [color_path, ref] : COLOR.pending_refs) {
      dbc::check(COLOR.palettes.contains(ref),
          fmt::format("In {} you have {} referring to {} but {} doesn't exist.",
            COLOR.config, color_path, ref, ref));
      dbc::check(!COLOR.palettes.contains(color_path),
          fmt::format("Color {} with ref {} is duplicated.", color_path, ref));

      auto color = COLOR.palettes.at(ref);

      COLOR.palettes.try_emplace(color_path, color);
    }
  }

  sf::Color get(const string& key) {
    dbc::check(COLOR.palettes.contains(key),
        fmt::format("COLOR {} is missing from {}", key, COLOR.config));
    return COLOR.palettes.at(key);
  }

  sf::Color get(const string& key, const string& value) {
    return get(key + ":" + value);
  }
}
