#pragma once

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/walk_object_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/task.h>

#include <maps/infra/yacare/include/yacare.h>

#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/http/include/etag.h>
#include <maps/libs/deprecated/localeutils/include/locale.h>
#include <maps/libs/sproto/include/well_formed.h>

#include <sstream>

namespace maps::mrc::agent_proxy {

const std::string CONTENT_TYPE = "Content-Type";
const std::string CONTENT_TYPE_PROTOBUF = "application/x-protobuf";
const std::string ETAG = "ETag";


#define CHECK_REQ(cond, msg)                            \
    do {                                                \
        if (!Y_LIKELY(cond)) {                          \
            throw yacare::errors::BadRequest() << msg;  \
        }                                               \
    } while (0)


void errorReporter(const yacare::Request&, yacare::Response& resp);

http::ETag makeEtag(size_t hash);

http::ETag makeEtag(const std::string& data);

template<typename Units>
std::string internationalize(const std::locale& stdLocale, const Units& value)
{
    std::ostringstream ss;
    ss.imbue(stdLocale);
    ss << value;
    return ss.str();
}

const std::string& findBestTaskName(
    const db::ugc::Task& task,
    const Locale& locale);

std::pair<chrono::TimePoint, chrono::TimePoint>
readFirstAndLastRecordTimestamps(const std::string& data);

/// Checks that user is able to upload ugc data
/// otherwise throws YacareProtobufError
void checkUserCanPublishUgcContent(const yacare::Request& request);

template<typename ProtobufObject>
class YacareProtobufError : public yacare::Error {
public:
    YacareProtobufError(yacare::Status status, ProtobufObject object)
        : yacare::Error(static_cast<unsigned>(status))
        , object_(std::move(object))
    {
        sproto::assertWellFormed(object_);
    }

    void format(yacare::Response& response) const override
    {
        response.setStatus(status());
        response[CONTENT_TYPE] = CONTENT_TYPE_PROTOBUF;
        response << object_;
    }

private:
    ProtobufObject object_;
};


template <class ObjectType>
db::WalkFeedbackType decodeFeedbackType(ObjectType objectType)
{
    switch (objectType) {
    case ObjectType::UNKNOWN_OBJECT_TYPE:
        return db::WalkFeedbackType::None;
    case ObjectType::BARRIER:
        return db::WalkFeedbackType::Barrier;
    case ObjectType::OTHER:
        return db::WalkFeedbackType::Other;
    case ObjectType::BUILDING_ENTRANCE:
        return db::WalkFeedbackType::BuildingEntrance;
    case ObjectType::ADDRESS_PLATE:
        return db::WalkFeedbackType::AddressPlate;
    case ObjectType::ENTRANCE_PLATE:
        return db::WalkFeedbackType::EntrancePlate;
    case ObjectType::BUSINESS_SIGN:
        return db::WalkFeedbackType::BusinessSign;
    case ObjectType::BUSINESS_WORKING_HOURS:
        return db::WalkFeedbackType::BusinessWorkingHours;
    case ObjectType::FOOT_PATH:
        return db::WalkFeedbackType::FootPath;
    case ObjectType::CYCLE_PATH:
        return db::WalkFeedbackType::CyclePath;
    case ObjectType::STAIRS:
        return db::WalkFeedbackType::Stairs;
    case ObjectType::RAMP:
        return db::WalkFeedbackType::Ramp;
    case ObjectType::ROOM:
        return db::WalkFeedbackType::Room;
    case ObjectType::WALL:
        return db::WalkFeedbackType::Wall;
    case ObjectType::ORGANIZATION:
        return db::WalkFeedbackType::Organization;
    case ObjectType::FENCE:
        return db::WalkFeedbackType::Fence;
    case ObjectType::BUILDING:
        return db::WalkFeedbackType::Building;
    case ObjectType::PARKING:
        return db::WalkFeedbackType::Parking;

    default:
        throw yacare::errors::BadRequest() << "Unexpected feedback object type " << objectType;
    }
}


} //maps::mrc::agent_proxy
