#pragma once

#include <maps/libs/geolib/include/point.h>

#include <mapreduce/yt/interface/client.h>
#include <library/cpp/geobase/lookup.hpp>

#include <cstdint>
#include <memory>
#include <unordered_map>
#include <vector>

namespace maps::mrc::geobase {

struct GeobaseRegion {
    int32_t id;
    int32_t type;
    std::string name;
};

class GeobaseInterface {
public:
    virtual ~GeobaseInterface() = default;

    virtual GeobaseRegion getRegionById(int32_t id) const = 0;
    virtual std::vector<int32_t> getRegionParentIds(int32_t id) const = 0;
    virtual int32_t getRegionIdByLocation(
        const geolib3::Point2& geoPoint) const = 0;
};

using GeobasePtr = std::shared_ptr<GeobaseInterface>;

class Geobase6Adapter : public GeobaseInterface {
public:
    Geobase6Adapter(const std::string& path) : geobaseLookup_(path) {}

    GeobaseRegion getRegionById(int32_t id) const override;
    std::vector<int32_t> getRegionParentIds(int32_t id) const override;
    int32_t getRegionIdByLocation(
        const geolib3::Point2& geoPoint) const override;

private:
    NGeobase::TLookup geobaseLookup_;
};

class PatchedGeobaseAdapter : public GeobaseInterface {
public:
    PatchedGeobaseAdapter(
        GeobasePtr geobasePtr,
        std::unordered_map<int32_t, GeobaseRegion> regions,
        std::unordered_multimap<int32_t, int32_t> regionToParentRegion);

    GeobaseRegion getRegionById(int32_t id) const override;
    std::vector<int32_t> getRegionParentIds(int32_t id) const override;
    int32_t getRegionIdByLocation(
        const geolib3::Point2& geoPoint) const override;

private:
    GeobasePtr geobasePtr_;
    std::unordered_map<int32_t, GeobaseRegion> regions_;
    std::unordered_multimap<int32_t, int32_t> regionToParentRegion_;
};

GeobasePtr loadPatchedGeobasePtr(
    NYT::IClientPtr ytClient,
    const std::string& geodataPatchYtDir,
    GeobasePtr geobasePtr);

} // namespace maps::mrc::geobase
