#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/load.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/secure_config.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/tvm_client.h>

#include <maps/wikimap/mapspro/services/mrc/libs/common/include/exif.h>
#include <maps/wikimap/mapspro/services/mrc/libs/common/include/load.h>
#include <maps/wikimap/mapspro/services/mrc/libs/common/include/opencv.h>
#include <maps/wikimap/mapspro/services/mrc/libs/common/include/panorama_utils.h>
#include <maps/wikimap/mapspro/services/mrc/libs/common/include/types.h>

namespace maps::mrc::eye {

FrameLoader::FrameLoader(
    const std::string& mrcMdsHost,
    const std::string& mrcMdsNamespace,
    int mrcMdsPort)
    : mrcMdsPrefix_("http://" + mrcMdsHost + ":" + std::to_string(mrcMdsPort) + "/get-" + mrcMdsNamespace)
{
}

FrameLoader FrameLoader::fromConfig(const common::Config& config)
{
    const mds::Configuration& mrc = config.makeMdsConfiguration();
    auto readPort = mrc.readPort();
    return FrameLoader(
        mrc.readHost(), mrc.namespaceName(), readPort ? *readPort : 80);
}

cv::Mat FrameLoader::load(const db::eye::Frame& frame) const
{
    auto image = common::decodeImage(loadRaw(frame.urlContext()));

    ASSERT(frame.originalSize() == common::sizeOf(image));

    return common::transformByImageOrientation(image, frame.orientation());
}

cv::Mat FrameLoader::load(const db::eye::UrlContext& urlContext, const common::ImageOrientation& orientation) const
{
    return common::transformByImageOrientation(
                common::decodeImage(loadRaw(urlContext)),
                orientation);
}

std::string FrameLoader::loadRaw(const db::eye::UrlContext& urlContext) const
{
    switch(auto source = urlContext.source()) {
        case db::eye::FrameSource::Mrc:
            return loadMrcRaw(urlContext.mrc());
        case db::eye::FrameSource::Panorama:
            return loadPanoramaRaw(urlContext.panorama());
        default:
            throw RuntimeError() << "Unknown source " << source;
    }
}

std::string FrameLoader::loadMrcRaw(const db::eye::MrcUrlContext& urlContext) const
{
    return common::load(mrcMdsPrefix_
            + "/" + urlContext.mdsGroupId
            + "/" + urlContext.mdsPath);
}

std::string FrameLoader::loadPanoramaRaw(
    const db::eye::PanoramaUrlContext& urlContext) const
{
    std::string tvmTicket;
    if (tvmClient()) {
        tvmTicket = tvmClient()->GetServiceTicketFor(
            PANORAMA_DESCRIPTION_SERVICE_ALIAS);
    }

    return common::loadPanoramaProjection(
        SecureConfig::instance().mrcConfig().externals().stvdescrUrl(),
        urlContext.oid,
        urlContext.heading,
        urlContext.tilt,
        urlContext.horizontalFOV,
        urlContext.size,
        tvmTicket);
}

} // namespace maps::mrc::eye
