#include "actions.hpp"

#include "data_db.hpp"
#include "settings.hpp"
#include "utils/error.hpp"
#include "utils/string.hpp"

namespace monitarr {
auto create_client(const server_cfg &server) -> httplib::Client {
  httplib::Client cli{server.url};
  cli.set_default_headers({
      {"X-Api-Key", server.api_key},
  });

  return cli;
}

auto get_download(std::uint64_t record_id, const server_cfg &server)
    -> std::optional<nlohmann::json> {
  MONITARR_USES_FUNCTION_NAME();

  auto cli = create_client(server);

  std::uint16_t page{0U};
  while (++page != 0U) {
    httplib::Params params;
    params.emplace("page", std::to_string(page));
    params.emplace("pageSize", "100");

    auto response =
        cli.Get(fmt::format("/api/{}/queue", server.api_version), params, {});
    if (response->status != httplib::StatusCode::OK_200) {
      utils::error::handle_error(
          function_name, fmt::format("check server request failed|{}|{}|{}",
                                     server.id, server.url, response->status));
      return std::nullopt;
    }

    auto json_data = nlohmann::json::parse(response->body);
    if (json_data.at("page").get<std::uint32_t>() != page) {
      return std::nullopt;
    }

    auto iter = std::ranges::find_if(
        json_data.at("records"),
        [&record_id](const nlohmann::json &record) -> bool {
          return record_id == record.at("id").get<std::uint64_t>();
        });
    if (iter == json_data.at("records").end()) {
      continue;
    }

    return *iter;
  }

  return std::nullopt;
}

auto list_queue(const server_cfg &server) -> int {
  MONITARR_USES_FUNCTION_NAME();

  auto cli = create_client(server);

  std::uint16_t page{0U};
  while (++page != 0U) {
    httplib::Params params;
    params.emplace("page", std::to_string(page));
    params.emplace("pageSize", "100");

    auto response =
        cli.Get(fmt::format("/api/{}/queue", server.api_version), params, {});
    if (response->status != httplib::StatusCode::OK_200) {
      utils::error::handle_error(
          function_name, fmt::format("check server request failed|{}|{}|{}",
                                     server.id, server.url, response->status));
      return 3;
    }

    auto json_data = nlohmann::json::parse(response->body);
    if (json_data.at("page").get<std::uint32_t>() != page) {
      break;
    }

    utils::error::handle_info(
        function_name, fmt::format("{}", json_data.at("records").dump(2)));
  }

  return 0;
}

void remove_stalled(std::string_view download_id, std::string_view title,
                    std::uint64_t episode_id, std::uint64_t movie_id,
                    const server_cfg &server, data_db *state_db) {
  MONITARR_USES_FUNCTION_NAME();

  fmt::println("remove and block {}|{}|{}|{}", server.id, server.url, title,
               download_id);

  if (state_db != nullptr) {
    state_db->remove(download_id);
  }

  auto cli = create_client(server);
  auto response = cli.Delete(
      fmt::format("/api/{}/queue/{}?blocklist=true&skipRedownload=false",
                  server.api_version,
                  utils::string::split(download_id, '/', false).at(1U)));
  if (response->status != httplib::StatusCode::OK_200) {
    utils::error::handle_error(
        function_name, fmt::format("failed to delete download|{}|{}|{}",
                                   server.id, server.url, response->status));
    return;
  }

  if (utils::string::contains("radarr", server.id)) {
    nlohmann::json data({
        {"name", "MoviesSearch"},
        {"movieIds", {movie_id}},
    });

    response = cli.Post(fmt::format("/api/{}/command", server.api_version),
                        data.dump(), "application/json");
    if (response->status != httplib::StatusCode::Created_201) {
      utils::error::handle_error(function_name,
                                 fmt::format("failed to search|{}|{}|{}|{}|{}",
                                             server.id, server.url, title,
                                             movie_id, response->status));
    }
    return;
  }

  if (not utils::string::contains("sonarr", server.id)) {
    return;
  }

  nlohmann::json data({
      {"name", "EpisodeSearch"},
      {"episodeIds", {episode_id}},
  });

  response = cli.Post(fmt::format("/api/{}/command", server.api_version),
                      data.dump(), "application/json");
  if (response->status != httplib::StatusCode::Created_201) {
    utils::error::handle_error(function_name,
                               fmt::format("failed to search|{}|{}|{}|{}|{}",
                                           server.id, server.url, title,
                                           episode_id, response->status));
  }
}

} // namespace monitarr
