#pragma once

#include "common.h"
#include "txn_id.h"

#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/sql_chemistry/include/gateway_access.h>
#include <maps/libs/geolib/include/heading.h>
#include <maps/libs/geolib/include/point.h>

#include <string>

namespace maps::mrc::db {

using PanoramaOID = std::string;

class EyePanorama {
public:
    EyePanorama(
        const PanoramaOID& oid,
        chrono::TimePoint date,
        std::uint64_t sessionId,
        std::uint32_t orderNum,
        geolib3::Point2 geodeticPos,
        geolib3::Heading vehicleCourse,
        bool deleted)
        : oid_{oid}
        , date_{date}
        , sessionId_{sessionId}
        , orderNum_{orderNum}
        , geodeticPos_{geodeticPos}
        , vehicleCourseDeg_{(float)vehicleCourse.value()}
        , deleted_{deleted} {};

    // Unique external panorama ID
    const PanoramaOID oid() const { return oid_; }

    TId txnId() const { return txnId_; }

    chrono::TimePoint date() const { return date_; }

    // ID of a shooting session a panorama was taken in
    std::uint64_t sessionId() const { return sessionId_; }

    // A panorama order number within its shooting session
    std::uint32_t orderNum() const { return orderNum_; }

    const geolib3::Point2& geodeticPos() const { return geodeticPos_; }

    geolib3::Point2 mercatorPos() const
    {
        return geolib3::convertGeodeticToMercator(geodeticPos());
    }

    // Azimuth a shooting vehicle is directed to
    geolib3::Heading vehicleCourse() const
    {
        return geolib3::Heading{vehicleCourseDeg_};
    }

    // Flag marking deleted panoramas
    bool deleted() const { return deleted_; }

    EyePanorama& setDeleted(bool deleted)
    {
        deleted_ = deleted;
        return *this;
    }

private:
    friend class sql_chemistry::GatewayAccess<EyePanorama>;
    friend class TxnIdAccess<EyePanorama>;

    EyePanorama() = default;

    EyePanorama& setTxnId(TId txnId) {
        txnId_ = txnId;
        return *this;
    }

    template<typename T>
    static auto introspect(T& t)
    {
        return std::tie(
            t.oid_,
            t.txnId_,
            t.date_,
            t.sessionId_,
            t.orderNum_,
            t.geodeticPos_,
            t.vehicleCourseDeg_,
            t.deleted_);
    }

    PanoramaOID oid_{};
    TId txnId_{};
    chrono::TimePoint date_{};
    std::uint64_t sessionId_{};
    std::uint32_t orderNum_{};
    geolib3::Point2 geodeticPos_{};
    float vehicleCourseDeg_{};
    bool deleted_{};

public:
    auto introspect() const { return introspect(*this); }
};

using PanoramaOIDs = std::vector<PanoramaOID>;
using EyePanoramas = std::vector<EyePanorama>;

} // namespace maps::mrc::db
