#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/url.h>

#include <maps/wikimap/mapspro/services/mrc/libs/common/include/types.h>

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

namespace maps::mrc::eye {

FrameUrlResolver::FrameUrlResolver(
    const http::URL& browserUrl,
    const http::URL& browserProUrl)
    : browserUrl_(browserUrl)
    , browserProUrl_(browserProUrl)
{}

http::URL FrameUrlResolver::getBrowserUrl(db::FeaturePrivacy privacy) const {
    if (privacy == db::FeaturePrivacy::Secret) {
        return browserProUrl_;
    } else {
        return browserUrl_;
    }
}

std::string FrameUrlResolver::makeMrcPreviewUrl(
    const db::eye::MrcUrlContext& urlContext,
    db::FeaturePrivacy privacy) const
{
    http::URL imageUrl = getBrowserUrl(privacy);
    imageUrl.setPath("/feature/" + std::to_string(urlContext.featureId) + "/thumbnail");

    return imageUrl.toString();
}

std::string FrameUrlResolver::makeMrcUrl(
    const db::eye::MrcUrlContext& urlContext,
    const common::ImageOrientation& orientation,
    db::FeaturePrivacy privacy) const
{
    http::URL imageUrl = getBrowserUrl(privacy);
    imageUrl.setPath("/feature/" + std::to_string(urlContext.featureId) + "/image");
    imageUrl.setParams("orientation=" + std::to_string(static_cast<int32_t>(orientation)));

    return imageUrl.toString();
}

std::string FrameUrlResolver::makePanoramaPreviewUrl(
    const db::eye::PanoramaUrlContext& urlContext) const
{
    return makePanoramaUrl(urlContext,
                           common::getThumbnailSize(urlContext.size));
}

std::string FrameUrlResolver::makePanoramaUrl(
    const db::eye::PanoramaUrlContext& urlContext,
    const std::optional<common::Size>& size) const
{
    http::URL imageUrl = getBrowserUrl(db::FeaturePrivacy::Public);

    imageUrl.setPath("/v2/pano/" + urlContext.oid + "/image");
    imageUrl.addParam("heading", std::to_string(urlContext.heading.value()));
    imageUrl.addParam("tilt", std::to_string(urlContext.tilt.value()));
    imageUrl.addParam("hfov", std::to_string(urlContext.horizontalFOV.value()));

    if (size) {
        imageUrl.addParam("size",
                          std::to_string(size->width)
                          + "," +
                          std::to_string(size->height));
    } else {
        imageUrl.addParam("size",
                          std::to_string(urlContext.size.width)
                          + "," +
                          std::to_string(urlContext.size.height));
    }

    return imageUrl.toString();
}

std::string FrameUrlResolver::preview(
    const db::eye::Frame& frame,
    db::FeaturePrivacy privacy) const
{
    const auto urlContext = frame.urlContext();

    switch (auto source = urlContext.source()) {
        case db::eye::FrameSource::Mrc:
            return makeMrcPreviewUrl(urlContext.mrc(), privacy);
        case db::eye::FrameSource::Panorama:
            return makePanoramaPreviewUrl(urlContext.panorama());
        default:
            throw RuntimeError() << "Unknown source " << source;
    };
}

std::string FrameUrlResolver::image(
    const db::eye::Frame& frame,
    const common::ImageOrientation& orientation,
    db::FeaturePrivacy privacy) const
{
    const auto urlContext = frame.urlContext();

    switch (auto source = urlContext.source()) {
        case db::eye::FrameSource::Mrc:
            return makeMrcUrl(urlContext.mrc(), orientation, privacy);
        case db::eye::FrameSource::Panorama:
            return makePanoramaUrl(urlContext.panorama());
        default:
            throw RuntimeError() << "Unknown source " << source;
    };
}

std::string FrameUrlResolver::image(
    const db::eye::Frame& frame,
    db::FeaturePrivacy privacy) const
{
    return image(frame, frame.orientation(), privacy);
}

} // namespace maps::mrc::eye
