#include "serialize.h"

#include <maps/libs/json/include/value.h>
#include <maps/libs/json/include/builder.h>

#include <maps/libs/common/include/exception.h>

namespace maps {
namespace wiki {
namespace ft_fix {

namespace category {
const std::string PREFIX = "cat:";
const std::string TRANSPORT_STOP = "transport_stop";
const std::string TRANSPORT_BUS_ROUTE = "transport_bus_route";
const std::string TRANSPORT_TROLLEY_ROUTE = "transport_trolleybus_route";
const std::string TRANSPORT_TRAM_ROUTE = "transport_tram_route";
const std::string TRANSPORT_MINIBUS_ROUTE = "transport_minibus_route";


const std::string TRANSPORT_NM = "transport_nm";
} // namespace category

namespace attr {
const std::string NAME = ":name";
const std::string LANG = ":lang";
const std::string IS_LOCAL = ":is_local";
const std::string TYPE = ":type";
const std::string DISP_CLASS = ":disp_class";
} // namespace attr

namespace role {
const std::string ASSIGNED = "assigned";
const std::string OFFICIAL = "official";
} // namespace role



namespace jkey {
const std::string ATTRIBUTES = "attributes";
const std::string TYPE = "type";
const std::string COORDINATES = "coordinates";
const std::string POLYGON = "Polygon";
const std::string OBJECTS = "objects";
const std::string RELATIONS = "relations";
const std::string MASTER = "master";
const std::string SLAVE = "slave";

const std::string REL_MASTER = "rel:master";
const std::string REL_SLAVE = "rel:slave";
const std::string REL_ROLE = "rel:role";

const std::string EXTENDS = "extends";
const std::string CATEGORY = "category";
const std::string FILES = "files";
const std::string PAGE_INDEX = "page_index";
const std::string PAGE_COUNT = "page_count";
const std::string OBJECTS_COUNT = "objects_count";

const std::string DESCRIPTION = "description";
} // namespace jkey

namespace {

const std::string&
routeCategory(RouteType type)
{
    switch(type) {
        case RouteType::Bus:
            return category::TRANSPORT_BUS_ROUTE;
        case RouteType::Trolley:
            return category::TRANSPORT_TROLLEY_ROUTE;
        case RouteType::Tram:
            return category::TRANSPORT_TRAM_ROUTE;
        case RouteType::Minibus:
            return category::TRANSPORT_MINIBUS_ROUTE;
        default:
            throw(maps::Exception() << "Unknown RouteType " << static_cast<int>(type));
    }
}

} // namespace

void
serializeJson(std::ostream& os, const Routes& routes, uint64_t idStartFrom)
{
    size_t id = idStartFrom;
    json::Builder builder(os);

    builder << [&](json::ObjectBuilder builder) {
        builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
            builder[jkey::DESCRIPTION] = "Masstransit routes initial migration";
        };
        builder[jkey::OBJECTS] = [&](json::ObjectBuilder builder) {
            for (const auto& route: routes) {
                auto routeNmId = ++id;
                auto routeId = ++id;
                auto routeCat = routeCategory(route.descr.type);
                builder[std::to_string(routeNmId)] = [&](json::ObjectBuilder builder) {
                    builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
                        builder[category::PREFIX + category::TRANSPORT_NM] = "1";
                        builder[category::TRANSPORT_NM + attr::NAME] = route.descr.name;
                        builder[category::TRANSPORT_NM + attr::LANG] = "ru";
                        builder[category::TRANSPORT_NM + attr::IS_LOCAL] = "1";
                    };
                    builder[jkey::RELATIONS] = [&](json::ArrayBuilder builder) {
                        builder << [&](json::ObjectBuilder builder) {
                            builder[jkey::MASTER] = std::to_string(routeId);
                            builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
                                builder[jkey::REL_MASTER] = routeCat;
                                builder[jkey::REL_ROLE] = role::OFFICIAL;
                                builder[jkey::REL_SLAVE] = category::TRANSPORT_NM;
                            };
                        };
                    };
                };
                builder[std::to_string(routeId)] = [&](json::ObjectBuilder builder) {
                    builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
                        builder[category::PREFIX + routeCat] = "1";
                        builder[routeCat + attr::DISP_CLASS] = "5";
                    };
                    builder[jkey::RELATIONS] = [&](json::ArrayBuilder builder) {
                        for (const auto& stopId: route.stopIds) {
                            builder << [&](json::ObjectBuilder builder) {
                                builder[jkey::SLAVE] = std::to_string(stopId);
                                builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
                                    builder[jkey::REL_MASTER] = routeCat;
                                    builder[jkey::REL_ROLE] = role::ASSIGNED;
                                    builder[jkey::REL_SLAVE] = category::TRANSPORT_STOP;
                                };
                            };
                        }
                    };
                };
            }
        };
    };
}


} // namespace ft_fix
} // namespace wiki
} // namespace maps
