#pragma once

#include "route.h"

#include <yandex/maps/wiki/http/fbapi/models/task.h>
#include <yandex/maps/wiki/social/feedback/description.h>
#include <yandex/maps/wiki/social/feedback/description_producers.h>
#include <yandex/maps/wiki/social/feedback/task.h>
#include <maps/libs/common/include/exception.h>
#include <maps/libs/geolib/include/point.h>

#include <functional>
#include <optional>
#include <string>

namespace maps::wiki::sync_fbapi_feedback {

class IUriResolver
{
public:
    virtual std::optional<std::string> resolveObjectUri(const std::string&) = 0;
    virtual std::optional<Route> resolveDrivingRouteUri(const std::string&) = 0;
    virtual std::optional<Route> resolveMtRouteUri(const std::string&) = 0;
    virtual std::optional<Route> resolvePedestrianRouteUri(const std::string&) = 0;
    virtual std::optional<Route> resolveBicycleRouteUri(const std::string&) = 0;
    virtual std::optional<Route> resolveScooterRouteUri(const std::string&) = 0;
    virtual ~IUriResolver();
};

class IssueParseError : public maps::RuntimeError
{};

class FbapiIssueParser
{
public:
    explicit FbapiIssueParser(IUriResolver& uriResolver, const fbapi::Task& task);

    const geolib3::Point2& position() const { return position_; }
    social::feedback::Type type() const { return type_; }
    const std::string& source() const { return source_; }
    const social::feedback::Description& description() const { return description_; }
    const std::optional<social::TId>& objectId() const { return objectId_; }
    const std::optional<bool>& hidden() const { return hidden_; }
    const social::feedback::Attrs& attrs() const { return attrs_; }

private:
    void initAddressRelatedProperties(
        social::feedback::AddressDescriptionType addressDescriptionType);

    void initAddObjectBarrier();
    void initAddObjectCrosswalk();
    void initAddObjectEntrance();
    void initAddObjectFence();
    void initAddObjectGate();
    void initAddObjectOther();
    void initAddObjectParking();
    void initAddObjectRoad();
    void initAddObjectStop();
    void initAddObjectToponym();
    void initFromOtherContext(
        social::feedback::Type type,
        const std::string& tankerKey);
    void initWithCommentOrPhotoRequired(
        social::feedback::Type type,
        const std::string& tankerKey);
    void initRemoveObjectToponym();
    void initReportLocation();
    void initWrongAddressDontKnow();
    void initWrongAddressReportAddress();
    void initWrongAddressReportLocation();
    void initWrongBarrierNotFound(const std::string& descriptionKey);
    void initWrongBarrierReportLocation(const std::string& descriptionKey);
    void initWrongEntranceNotFound();
    void initWrongEntranceReportEntrance();
    void initWrongEntranceReportLocation();
    void initWrongLinesReportLines();
    void initWrongLocationReportLocation();
    void initWrongNameReportName();
    void initWrongPositionDemolished();
    void initWrongPositionNeverBeenHere();
    void initWrongPositionNotFound();
    void initWrongPositionOther();
    void initWrongRouteReportRoute(IUriResolver& uriResolver);
    void initWrongSubwayReportSubway();
    void initWrongSubwayNotFound();

    void initCommonFields(IUriResolver& uriResolver, const fbapi::Task& task);

    fbapi::OriginalTask originalTask_;
    geolib3::Point2 position_;
    social::feedback::Type type_;
    std::string source_;
    social::feedback::Description description_;
    std::optional<social::TId> objectId_;
    std::optional<bool> hidden_;
    social::feedback::Attrs attrs_;
};

} // namespace maps::wiki::sync_fbapi_feedback
