#include <maps/wikimap/ugc/backoffice/src/lib/request_validator.h>
#include <maps/infra/yacare/include/error.h>

namespace maps::wiki::ugc::backoffice {

RequestValidator::RequestValidator(const maps::json::Value& config)
{
    const auto prefixesConf = config["prefixes"];
    for (const std::string& field : prefixesConf.fields()) {
        maps::auth::TvmId tvmId = std::stoul(field);
        for (const auto& value : prefixesConf[field]) {
            allowedPrefixes_[tvmId].insert(value.as<std::string>());
        }
    }
    const auto metadataConf = config["metadata"];
    for (const std::string& field : metadataConf.fields()) {
        maps::auth::TvmId tvmId = std::stoul(field);
        for (const auto& value : metadataConf[field]) {
            allowedMetadatas_[tvmId].emplace(value.as<int>());
        }
    }
    if (config.hasField("require_geometry")) {
        for (const auto& jsonValue : config["require_geometry"]) {
            requireGeometry_.emplace(jsonValue.as<int>());
        }
    }
}

void RequestValidator::checkId(maps::auth::TvmId tvmId, const std::string& id) const
{
    const auto prefixesIt = allowedPrefixes_.find(tvmId);
    REQUIRE(
        prefixesIt != allowedPrefixes_.end(),
        yacare::errors::Forbidden() << "Unknown tvm id: " << tvmId << "; add it to service config"
    );
    auto colonPos = id.find(':');
    REQUIRE(
        colonPos != std::string::npos,
        yacare::errors::BadRequest() << "Missing prefix in id " << id
    );
    REQUIRE(
        prefixesIt->second.contains(id.substr(0, colonPos)),
        yacare::errors::Forbidden() << "Forbidden id " << id << " for tvm id = " << tvmId
    );
}

void RequestValidator::checkMetadataId(maps::auth::TvmId tvmId, MetadataId id) const
{
    const auto metadatasIt = allowedMetadatas_.find(tvmId);
    REQUIRE(
        metadatasIt != allowedMetadatas_.end(),
        yacare::errors::Forbidden() << "Unknown tvm id: " << tvmId << "; add it to service config"
    );
    REQUIRE(
        metadatasIt->second.contains(id),
        yacare::errors::Forbidden() << "Forbidden metadata id " << id << " for tvm id = " << tvmId
    );
}

void RequestValidator::checkGeometry(const proto::backoffice::Task& task, MetadataId id) const
{
    if (requireGeometry_.contains(id)) {
        REQUIRE(
            task.has_point(),
            yacare::errors::BadRequest() << "Task with metadata id " << id << " must have geometry"
        );
    }
}

} // maps::wiki::ugc::backoffice
