#pragma once
#include <maps/libs/geolib/include/polygon.h>
#include <maps/libs/geolib/include/multipolygon.h>

#include <contrib/libs/geos/include/geos/geom/Geometry.h>

#include <vector>
#include <optional>

namespace maps {
namespace wiki {
namespace autocart {

/**
 * @brief Извлекает набор полигонов из заданного объекта.
 *     Если объект является мультиполигоном, то он разбивается
 *     на несколько полигонов, которые хранятся поотдельности
 * @param geom  геометрия объекта
 * @return набор полигонов, содержащихся в объекте
 */
std::vector<geolib3::Polygon2>
extractPolygons(const geos::geom::Geometry& geom);

/**
 * @brief Rotates polygon around point
 * @param polygon      polygon
 * @param angleDegree  angle of rotation in degree
 * @param center       center of rotation
 * @return             rotated polygon
 */
geolib3::Polygon2 rotatePolygon(const geolib3::Polygon2& polygon,
                                float angleDegree,
                                const geolib3::Point2& center);

/**
 * @brief Rotates polygon around centroid
 * @param polygon      polygon
 * @param angleDegree  angle of rotation in degree
 * @return             rotated polygon
 */
geolib3::Polygon2 rotatePolygon(const geolib3::Polygon2& polygon,
                                float angleDegree);

/**
 * @brief Finds intersection of two polygons.
 * @param polygon1  polygon for intersection
 * @param polygon2  polygon for intersection
 * @return          set of intersecting polygons
 */
geolib3::MultiPolygon2
intersectPolygons(
    const geolib3::Polygon2& polygon1,
    const geolib3::Polygon2& polygon2);

/**
 * @brief Finds intersection of two multiPolygons.
 * @param multiPolygon1  multiPolygon for intersection
 * @param multiPolygon2  multiPolygon for intersection
 * @return          set of intersecting polygons
 */
geolib3::MultiPolygon2
intersectMultiPolygons(
    const geolib3::MultiPolygon2& multiPolygon1,
    const geolib3::MultiPolygon2& multiPolygon2);

/**
 * @brief Merge set of polygons.
 * @param polygons  polygons for merging
 * @return          set of merged polygons
 */
geolib3::MultiPolygon2
mergePolygons(const std::vector<geolib3::Polygon2>& polygons);

geolib3::MultiPolygon2
cascadedMergePolygons(const std::vector<geolib3::Polygon2>& polygons);

/**
 * @brief Merge set of multiPolygons.
 * @param multiPolygons  multiPolygons for merging
 * @return               set of merged polygons
 */
geolib3::MultiPolygon2
mergeMultiPolygons(const std::vector<geolib3::MultiPolygon2>& multiPolygons);

geolib3::MultiPolygon2
cascadedMergeMultiPolygons(const std::vector<geolib3::MultiPolygon2>& multiPolygons);

/**
 * @brief Finds area of intersection of two polygons
 * @param polygon1  polygon for intersection
 * @param polygon2  polygon for intersection
 * @return          area of intersection
 */
double intersectionArea(const geolib3::Polygon2& polygon1,
                        const geolib3::Polygon2& polygon2);

/**
 * @brief Finds intersection over union of two polygons.
 *     (https://en.wikipedia.org/wiki/Jaccard_index)
 * @param polygon1  polygon for intersection
 * @param polygon2  polygon for intersection
 * @return          value of IoU metric
 */
double IoU(const geolib3::Polygon2& polygon1, const geolib3::Polygon2& polygon2);

geolib3::MultiPolygon2
differenceMultiPolygons(
    const geolib3::MultiPolygon2& multiPolygon1,
    const geolib3::MultiPolygon2& multiPolygon2);

} //namespace autocart
} //namespace wiki
} //namespace maps
