#include <maps/wikimap/mapspro/services/autocart/libs/geometry/include/hex_wkb.h>
#include <maps/wikimap/mapspro/services/autocart/libs/geometry/include/polygon_processing.h>

#include <maps/libs/common/include/exception.h>

#include <maps/libs/geolib/include/polygon.h>
#include <maps/libs/geolib/include/polyline.h>
#include <maps/libs/geolib/include/conversion.h>

#include <contrib/libs/geos/include/geos/geom/Geometry.h>
#include <contrib/libs/geos/include/geos/geom/Polygon.h>
#include <contrib/libs/geos/include/geos/geom/LineString.h>
#include <contrib/libs/geos/include/geos/geom/GeometryFactory.h>
#include <contrib/libs/geos/include/geos/io/WKBReader.h>
#include <contrib/libs/geos/include/geos/io/WKBWriter.h>

#include <vector>
#include <string>

namespace maps::wiki::autocart {

namespace {

template <typename T>
std::string geolib2hexWKB(const T& object) {
    auto geom = geolib3::internal::geolib2geosGeometry(object);
    std::stringstream ss;
    geos::io::WKBWriter().writeHEX(*geom, ss);
    return ss.str();
}

} // namespace

geolib3::MultiPolygon2 hexWKBToMultiPolygon(std::string_view hexWKB) {
    std::stringstream ss(std::string{hexWKB});
    std::unique_ptr<geos::geom::Geometry> g(geos::io::WKBReader().readHEX(ss));
    return geolib3::MultiPolygon2(extractPolygons(*g));
}

std::string multiPolygonToHexWKB(const geolib3::MultiPolygon2& multipolygon) {
    return geolib2hexWKB(multipolygon);
}

geolib3::Polygon2 hexWKBToPolygon(std::string_view hexWKB) {
    std::stringstream ss(std::string{hexWKB});
    std::unique_ptr<geos::geom::Geometry> geom(geos::io::WKBReader().readHEX(ss));
    REQUIRE(dynamic_cast<geos::geom::Polygon*>(geom.get()),
            "Incorrect geometry type");
    auto polygon = geolib3::internal::geos2geolibGeometry(
                       dynamic_cast<geos::geom::Polygon*>(geom.get())
                   );
    return polygon;
}

std::string polygonToHexWKB(const geolib3::Polygon2& polygon) {
    return geolib2hexWKB(polygon);
}

geolib3::Polyline2 hexWKBToPolyline(std::string_view hexWKB) {
    std::stringstream ss(std::string{hexWKB});
    std::unique_ptr<geos::geom::Geometry> geom(geos::io::WKBReader().readHEX(ss));
    REQUIRE(dynamic_cast<geos::geom::LineString*>(geom.get()),
            "Incorrect geometry type");
    auto polyline = geolib3::internal::geos2geolibGeometry(
                        dynamic_cast<geos::geom::LineString*>(geom.get())
                    );
    return polyline;
}

std::string polylineToHexWKB(const geolib3::Polyline2& polyline) {
    return geolib2hexWKB(polyline);
}

} // namespace maps::wiki::autocart
