#pragma once

#include <maps/wikimap/mapspro/services/autocart/pipeline/libs/objects/include/bbox.h>

#include <mapreduce/yt/interface/client.h>

#include <set>
#include <vector>

namespace maps::wiki::autocart::pipeline {

struct Cell {
    static constexpr const char* X = "cell_x";
    static constexpr const char* Y = "cell_y";

    Cell(int64_t x, int64_t y);

    static Cell fromYTNode(const NYT::TNode& node);

    NYT::TNode toYTNode() const;
    void toYTNode(NYT::TNode& node) const;

    BBox toBBox(double cellSizeInMercator) const;

    bool operator==(const Cell& other) const;
    bool operator<(const Cell& other) const;

    int64_t x;
    int64_t y;
};

static const double DEFAULT_CELL_SIZE_MERCATOR = 1000.;
static const double DEFAULT_ADJACENT_DISTANCE_MERCATOR = 200.;

class DirectlyCellsCover {
public:
    Y_SAVELOAD_DEFINE(cellSizeMercator_, gridSize_);

    DirectlyCellsCover(
        double cellSizeMercator = DEFAULT_CELL_SIZE_MERCATOR);

    template <class GeomType>
    std::set<Cell> coverGeomByCells(const GeomType& geom) const;

private:
    double cellSizeMercator_;
    int64_t gridSize_;
};


class AdjacentCellsCover {
public:
    Y_SAVELOAD_DEFINE(cellSizeMercator_, adjacentDistanceMercator_, gridSize_);

    AdjacentCellsCover();

    AdjacentCellsCover(
        double cellSizeMercator, double adjacentDistanceMercator);

    template <class GeomType>
    std::set<Cell> coverGeomByCells(const GeomType& geom) const;

private:
    template <class GeomType>
    bool isAdjacentCell(const Cell& cell, const GeomType& geom) const;

    void validateParams() const;

    double cellSizeMercator_;
    double adjacentDistanceMercator_;
    int64_t gridSize_;
};


template <class Object, class CoverType>
void coverObjectsByCells(
    NYT::IClientBasePtr client,
    const std::vector<TString>& inputYTTablesName,
    const CoverType& cover,
    const TString& outputYTTableName);

} // namespace maps::wiki::autocart::pipeline
