#pragma once

#include "common.h"
#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/geolib/include/point.h>
#include <maps/libs/json/include/value.h>

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

#include <istream>
#include <ostream>
#include <unordered_map>
#include <vector>

namespace maps::mrc::db {

enum class HypothesisType {
    WrongSpeedLimit,
    AbsentParking,
    WrongParkingFtType,
    TrafficSign,
    WrongDirection,
    ProhibitedPath,
};

DECLARE_ENUM_IO(HypothesisType);

class Hypothesis {
public:
    Hypothesis(
        HypothesisType type,
        geolib3::Point2 mercatorPos,
        TId objectId,
        TId commitId,
        TId signId);

    TId id() const { return id_; }

    HypothesisType type() const { return type_; }

    geolib3::Point2 mercatorPos() const { return mercatorPos_; }

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

    TId objectId() const { return objectId_; }

    TId commitId() const { return commitId_; }

    TId signId() const { return signId_; }

    const json::Value& context() const { return context_; }

    TId feedbackTaskId() const { return feedbackTaskId_; }

    Hypothesis& setContext(json::Value context);
    Hypothesis& setFeedbackTaskId(TId id);

private:
    friend class sql_chemistry::GatewayAccess<Hypothesis>;

    Hypothesis() = default;

    template <typename T>
    static auto introspect(T& t) {
        return std::tie(t.id_, t.type_, t.mercatorPos_, t.objectId_, t.commitId_,
            t.signId_, t.context_, t.feedbackTaskId_);
    }

    TId id_{};
    HypothesisType type_{};
    geolib3::Point2 mercatorPos_{};
    TId objectId_{};
    TId commitId_{};
    TId signId_{};
    json::Value context_{json::null};
    TId feedbackTaskId_{0};

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

using Hypotheses = std::vector<Hypothesis>;

} // namespace maps::mrc::db
