#pragma once

#include <maps/libs/geolib/include/multipolygon.h>
#include <yandex/maps/wiki/social/common.h>
#include <yandex/maps/wiki/social/involvement_filter.h>
#include <maps/libs/introspection/include/comparison.h>
#include <maps/libs/chrono/include/time_point.h>

#include <pqxx/pqxx>

#include <set>
#include <vector>
#include <optional>

namespace maps::wiki::social {

namespace involvement_name {
const std::string COND_RAILWAY_CROSSING = "cond_railway_crossing";
const std::string COND_SPEED_BUMP = "cond_speed_bump";
const std::string COND_TRAFFIC_LIGHT = "cond_traffic_light";
const std::string COVID = "covid";
const std::string CREATED_BARBEQUE = "created_barbeque";
const std::string CREATED_BENCHES = "created_benches";
const std::string CREATED_FENCES_LENGTH = "created_fences_length";
const std::string CREATED_PAVILION = "created_pavilion";
const std::string FLAT_RANGE = "flat_range";
const std::string MRC_FEEDBACK_MIRRORS = "mrc_feedback_mirrors";
const std::string MRC_FEEDBACK_ONFOOT = "mrc_feedback_onfoot";
const std::string PARKING_LOTS_LINEAR = "urban_roadnet_parking_lot_linear";
const std::string SPEED_LIMITS = "speed_limits";
const std::string UNPAVED_ROADS = "unpaved_roads";
} // namespace involvement_name

class Involvement;
using Involvements = std::vector<Involvement>;

class Involvement
{
public:
    /**
     * Will throw InvolvementNotFound upon attempt
     * to call writeToDatabase() if (id != 0) and
     * corresponding involvement doesn't exist
     */
    Involvement() = default;
    Involvement(
        TId id,
        std::string title,
        std::string url,
        std::set<std::string> types,
        Enabled enabled,
        chrono::TimePoint start
    );

    TId id() const;
    const std::string& title() const;
    const std::string& url() const;
    const std::set<std::string>& types() const;
    bool enabled() const;
    chrono::TimePoint start() const;
    const std::optional<chrono::TimePoint>& finish() const;
    const geolib3::MultiPolygon2& polygons() const;

    Involvement& setTitle(std::string title);
    Involvement& setUrl(std::string url);
    Involvement& setTypes(std::set<std::string> types);
    Involvement& setEnabled(Enabled enabled);
    Involvement& setStart(chrono::TimePoint start);
    Involvement& setFinish(const std::optional<chrono::TimePoint>& finish);
    Involvement& setPolygons(geolib3::MultiPolygon2 polygonsMerc);

    static Involvements byFilter(
        pqxx::transaction_base& socialTxn,
        const InvolvementFilter& filter
    );
    static Involvement byId(
        pqxx::transaction_base& socialTxn,
        TId id
    );

    void writeToDatabase(pqxx::transaction_base& socialTxn);

    auto introspect() const
    {
        return std::tie(id_, title_, url_, types_, enabled_, start_, finish_);
    }

private:
    TId id_;
    std::string title_;
    std::string url_;
    std::set<std::string> types_;
    Enabled enabled_;
    chrono::TimePoint start_;
    std::optional<chrono::TimePoint> finish_;

    /* Empty multipolygon means that counters for this involvement
     * will be calculated for the whole world
     */
    geolib3::MultiPolygon2 polygonsMerc_;
};
using introspection::operator<;
using introspection::operator==;

} //namespace maps::wiki::social
