#pragma once

#include "common.h"
#include "dataset_user.h"
#include "track_provider.h"
#include "video_events_feed.h"

#include <maps/libs/http/include/client.h>
#include <maps/libs/road_graph/include/graph.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/feature.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/import_taxi_event_config.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/video.h>
#include <maps/wikimap/mapspro/services/mrc/libs/fb/include/read.h>
#include <maps/wikimap/mapspro/services/mrc/libs/graph_matcher_adapter/include/compact_graph_matcher_adapter.h>
#include <maps/wikimap/mapspro/services/mrc/libs/privacy/include/geo_id_provider.h>
#include <maps/wikimap/mapspro/services/mrc/libs/video_frames_reader/include/frames_reader.h>
#include <yandex/maps/wiki/common/pgpool3_helpers.h>

#include <map>
#include <memory>

namespace maps::mrc::import_taxi {

class Importer {
public:
    Importer(
        pgpool3::Pool& pool,
        mds::Mds mdsClient,
        std::shared_ptr<VideoEventsFeed> videoEventsFeed,
        std::unique_ptr<ITrackProvider> trackProvider,
        const std::string& graphFolder,
        const std::string& geoIdPath,
        bool dryRun = false);

    void import();

    void setEventsFeed(std::shared_ptr<VideoEventsFeed>);

private:
    VideoEvents readEventsBatch();

    void importEvent(VideoEvent&&);

    using TGeoId = int64_t;
    using TFc = int16_t;
    using ThresholdsConfig = std::map<std::pair<TGeoId, TFc>, std::chrono::days>;
    using EventType = std::string;
    using TaxiEventsConfig = std::map<EventType, db::ImportTaxiEventConfig>;

    void refreshDatasets();

    void refreshThresholds();

    void refreshTaxiEventsConfig();

    bool segmentNeedsCoverage(
        const adapters::TrackSegment& segment,
        chrono::TimePoint videoTimestamp) const;

    std::string loadWithRetry(const std::string& url);

    db::Video saveVideo(
        pqxx::transaction_base& txn,
        const VideoEvent& videoEvent,
        chrono::TimePoint videoStartTime,
        std::chrono::milliseconds duration);

    db::Features savePhotos(
        pqxx::transaction_base& txn,
        video::VideoFramesReader&,
        const VideoEvent& videoEvent,
        chrono::TimePoint videoStartTime,
        const adapters::TrackSegments& trackSegments);

    db::Feature savePhoto(
        pqxx::transaction_base& txn,
        const cv::Mat& frame,
        const std::string& sourceId,
        chrono::TimePoint timestamp,
        const db::TrackPoint& location);

    void saveFrameToVideo(
        pqxx::transaction_base& txn,
        const db::Video& video,
        const db::Features& features,
        chrono::TimePoint videoStartTime);

    void saveTrackPoints(
        pqxx::transaction_base& txn,
        db::TrackPoints& trackPoints);

    pgpool3::Pool& pool_;
    mds::Mds mdsClient_;
    http::Client httpClient_;
    std::shared_ptr<VideoEventsFeed> videoEventsFeed_;
    std::unique_ptr<ITrackProvider> trackProvider_;

    DatasetUser<adapters::Matcher> graphMatcher_;
    DatasetUser<road_graph::Graph> graphReader_;
    DatasetUser<fb::GraphReader> graphCoverageReader_;
    DatasetUser<privacy::GeoIdProvider> geoIdProvider_;

    ThresholdsConfig thresholdsConfig_;
    TaxiEventsConfig taxiEventsConfig_;

    bool dryRun_;
};

} // namespace maps::mrc::import_taxi
