#pragma once

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

#include <maps/libs/sql_chemistry/include/gateway_access.h>
#include <maps/libs/geolib/include/polyline.h>
#include <maps/libs/enum_io/include/enum_io_fwd.h>

namespace maps::mrc::db::ugc {

enum class Direction {
    Forward,
    Backward,
    Bidirectional,
};

DECLARE_ENUM_IO(Direction);

enum class Traffic {
    RightHand,
    LeftHand,
};

DECLARE_ENUM_IO(Traffic);

enum class Oneway {
    No = false,
    Yes = true,
};

DECLARE_ENUM_IO(Oneway);

class Target {
public:
    Target() = default;

    Target(
        geolib3::Polyline2 geodeticGeom,
        Oneway oneway,
        Traffic traffic,
        Direction direction,
        std::optional<uint32_t> forwardPos = {},
        std::optional<uint32_t> backwardPos = {})
        : oneway_(static_cast<bool>(oneway))
        , traffic_(traffic)
        , direction_(direction)
        , geodeticGeom_(std::move(geodeticGeom))
        , forwardPos_(forwardPos)
        , backwardPos_(backwardPos) {
    }

    Target& setTaskId(TId id) {
        taskId_ = id;
        return *this;
    }

    TId id() const { return id_; }

    TId taskId() const { return taskId_; }

    const geolib3::Polyline2& geodeticGeom() const { return geodeticGeom_; }

    bool isOneway() const { return oneway_; }

    Traffic traffic() const { return traffic_; }

    Direction direction() const { return direction_; }

    /// Target position in task circular route
    std::optional<uint32_t> forwardPos() const { return forwardPos_; }

    std::optional<uint32_t> backwardPos() const { return backwardPos_; }

private:
    friend class sql_chemistry::GatewayAccess<Target>;
    friend class Task;

    template <typename T>
    static auto introspect(T& t) {
        return std::tie(t.id_, t.taskId_, t.oneway_, t.traffic_, t.direction_, t.geodeticGeom_,
            t.forwardPos_, t.backwardPos_);
    }

    TId id_{};
    TId taskId_{};
    bool oneway_{};
    Traffic traffic_{};
    Direction direction_{};
    geolib3::Polyline2 geodeticGeom_{};
    std::optional<uint32_t> forwardPos_{};
    std::optional<uint32_t> backwardPos_{};

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

using Targets = std::vector<Target>;

} // namespace maps::mrc::db::ugc
