#pragma once

#include <maps/wikimap/mapspro/libs/poi_feed/include/types.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/geolib/include/bounding_box.h>
#include <yandex/maps/wiki/common/string_utils.h>
#include <boost/optional.hpp>
#include <string>
#include <set>
#include <vector>

namespace maps::wiki::poi_feed {

using LocalizedString = maps::wiki::common::LocalizedString;

struct UnknownMappingData
{
    ObjectId nmapsId = 0;
    PermalinkId permalink = 0;
};

class FeedObjectData
{
public:
    enum class IsAdvert
    {
        Yes,
        No
    };

    enum class IsPlatinum
    {
        Yes,
        No
    };

    enum class HasOwner
    {
        Yes,
        No
    };

    enum class IsGeoproduct
    {
        Yes,
        No
    };

    struct Position
    {
        double lon = 0;
        double lat = 0;
        double distanceMeters(const Position& other) const;
        bool operator !=(const Position& other) const;
        geolib3::BoundingBox boundingBox() const;
    };

    FeedObjectData() = default;
    explicit FeedObjectData(const std::string& jsonString);

    std::string toJson() const;

    ObjectId nmapsId() const { return nmapsId_; }
    PermalinkId permalink() const { return permalink_; }
    bool toDelete() const { return toDelete_; }
    chrono::TimePoint actualizationDate() const { return actualizationDate_; }
    const std::set<LocalizedString>& names () const { return names_; }
    const std::set<LocalizedString>& shortNames() const { return shortNames_; }
    const boost::optional<Position>& position() const { return pos_; }
    const boost::optional<RubricId>& rubricId() const { return rubricId_; }
    const std::set<RubricId>& secondaryRubricIds() const { return secondaryRubricIds_; }
    const boost::optional<FtTypeId>& ftTypeId() const { return ftTypeId_; }
    const std::string& indoorLevelUniversal() const { return indoorLevelUniversal_; }
    bool isAdvert() const { return isAdvert_ == IsAdvert::Yes; }
    bool isPlatinum() const { return isPlatinum_ == IsPlatinum::Yes; }
    bool hasOwner() const { return hasOwner_ == HasOwner::Yes; }
    std::optional<ObjectId> indoorPlanId() const { return indoorPlanId_; }
    bool isGeoproduct() const { return isGeoproduct_ == IsGeoproduct::Yes; }


    void setNmapsId(ObjectId id) { nmapsId_ = id; }
    void setPermalink(PermalinkId permalinkId) { permalink_ = permalinkId; }
    void setToDelete(bool hasToBeDeleted) { toDelete_ = hasToBeDeleted; }
    void setActualizationDate(chrono::TimePoint timePoint) { actualizationDate_ = timePoint; }
    void addName(const LocalizedString& name) { names_.insert(name); }
    void setNames(const std::set<LocalizedString>& names) { names_ = names; }
    void addShortName(const LocalizedString& name) { shortNames_.insert(name); }
    void setShortNames(const std::set<LocalizedString>& names) { shortNames_ = names; }
    void setPosition (const Position& position) { pos_ = position; }
    void setRubricId(const boost::optional<RubricId>& rubricId) { rubricId_ = rubricId; }
    void addSecondaryRubric(RubricId rubricId) { secondaryRubricIds_.insert(rubricId); }
    void setFtTypeId(const boost::optional<FtTypeId>& ftTypeId) { ftTypeId_ = ftTypeId; }
    void setIndoorLevelUniversal(const std::string& indoorLevelUniversal) { indoorLevelUniversal_ = indoorLevelUniversal; }
    void setIsAdvert(IsAdvert isAdvert) { isAdvert_ = isAdvert; }
    void setIsPlatinum(IsPlatinum isPlatinum) { isPlatinum_ = isPlatinum; }
    void setHasOwner(HasOwner hasOwner) { hasOwner_ = hasOwner; }
    void setIndoorPlanId(const std::optional<ObjectId> indoorPlanId) { indoorPlanId_ = indoorPlanId; }
    void setIsGeoproduct(IsGeoproduct isGeoproduct) { isGeoproduct_ =  isGeoproduct; }

private:
    ObjectId nmapsId_ = 0;
    PermalinkId permalink_ = 0;
    bool toDelete_ = false;
    chrono::TimePoint actualizationDate_;
    std::set<LocalizedString> names_;
    std::set<LocalizedString> shortNames_;
    boost::optional<Position> pos_;
    boost::optional<RubricId> rubricId_;
    std::set<RubricId> secondaryRubricIds_;
    boost::optional<FtTypeId> ftTypeId_;
    std::string indoorLevelUniversal_;
    std::optional<IsAdvert> isAdvert_;
    std::optional<IsPlatinum> isPlatinum_;
    std::optional<HasOwner> hasOwner_;
    std::optional<ObjectId> indoorPlanId_;
    std::optional<IsGeoproduct> isGeoproduct_;
};

using FeedObjectDataVector = std::vector<FeedObjectData>;
} // namespace maps::wiki::poi_feed
