#include "io/io_module_usage.hpp"

#include "mission/mission_store.hpp"
#include "storage/map_store.hpp"
#include "util/string_util.hpp"

namespace lm {

namespace {

bool moduleRefMatches(const std::string& ref, const std::string& module_id, const std::string& module_name)
{
  const std::string needle = StringUtil::trimCopy(ref);
  if (needle.empty())
    return false;
  return needle == module_id || StringUtil::toLower(needle) == StringUtil::toLower(module_name);
}

void scanActions(const nlohmann::json& actions,
                 const std::string& module_id,
                 const std::string& module_name,
                 nlohmann::json& mission_hits)
{
  if (!actions.is_array())
    return;
  for (const auto& action : actions)
  {
    if (!action.is_object())
      continue;
    const auto& params = action.contains("params") && action["params"].is_object() ? action["params"]
                                                                                     : nlohmann::json::object();
    const std::string module_ref = params.value("module", params.value("module_id", ""));
    if (moduleRefMatches(module_ref, module_id, module_name))
    {
      mission_hits.push_back({{"mission_action", action.value("type", "")},
                              {"label", action.value("label", "")}});
    }
    if (action.contains("children"))
      scanActions(action["children"], module_id, module_name, mission_hits);
    if (action.contains("else_children"))
      scanActions(action["else_children"], module_id, module_name, mission_hits);
  }
}

}  // namespace

nlohmann::json findIoModuleUsages(const std::string& module_id,
                                  const std::string& module_name,
                                  MapStore& maps,
                                  MissionStore& missions)
{
  nlohmann::json zones = nlohmann::json::array();
  nlohmann::json mission_hits = nlohmann::json::array();

  for (const auto& map : maps.list())
  {
    if (!map.is_object())
      continue;
    const auto& zlist = map.value("zones", nlohmann::json::array());
    if (!zlist.is_array())
      continue;
    for (const auto& z : zlist)
    {
      if (!z.is_object() || z.value("type", "") != "io")
        continue;
      if (moduleRefMatches(z.value("io_module", ""), module_id, module_name))
      {
        zones.push_back({{"map_id", map.value("id", "")},
                         {"map_name", map.value("name", "")},
                         {"zone_id", z.value("id", "")}});
      }
    }
  }

  for (const auto& mission : missions.listMissions())
  {
    if (!mission.is_object())
      continue;
    const auto before = mission_hits.size();
    scanActions(mission.value("actions", nlohmann::json::array()), module_id, module_name, mission_hits);
    if (mission_hits.size() > before)
    {
      mission_hits.push_back({{"mission_id", mission.value("id", "")}, {"mission_name", mission.value("name", "")}});
    }
  }

  return {{"zones", zones}, {"missions", mission_hits}, {"in_use", !zones.empty() || !mission_hits.empty()}};
}

}  // namespace lm
