import union from '@turf/union'
import combine from '@turf/combine'
import { featureCollection, feature } from '@turf/helpers'
import GeoJSON from 'ol/format/GeoJSON'
import olGeomPolygon from 'ol/geom/Polygon'
import olGeomMultiPolygon from 'ol/geom/MultiPolygon'
import olGeomPoint from 'ol/geom/Point'
import olGeomLineString from 'ol/geom/LineString'
import olGeomMultiLineString from 'ol/geom/MultiLineString'
import olGeomCircle from 'ol/geom/Circle'
import olGeomMultiPoint from 'ol/geom/MultiPoint'

import ugh from 'ugh'

const format = new GeoJSON()
const projectionOpts = {
  dataProjection: 'EPSG:4326',
  featureProjection: 'EPSG:3857'
}


function combineGeos(geometries) {
    const collection = featureCollection(geometries)
    const fc = combine(collection)
    return fc.features[0].geometry
  }

function getNewGeoJsonGeom(feature, mergeFeature) {
    try {
        switch (feature.geometry.type) {
            case 'Point':
            case 'MultiPoint':
              return combineGeos([feature, mergeFeature])
            case 'LineString':
            case 'MultiLineString':
              return combineGeos([feature, mergeFeature])
            case 'Polygon':
            case 'MultiPolygon':
              return union(feature.geometry, mergeFeature.geometry).geometry
            default:
              return null
          }
    } catch (error) {
        return ugh.error(error)
    }   
}

function olFeatureToGeoJsonFeature(olFeature) {
  const clonedFeature = olFeature.clone()
  clonedFeature.unset('_ol_kit_parent')
  clonedFeature.setId(olFeature.getId())
  const geoJsonFeature = format.writeFeatureObject(clonedFeature, projectionOpts)
  geoJsonFeature.properties = Object.assign({}, geoJsonFeature.properties)
  return geoJsonFeature
}

function geoJsonGeomToOlGeom(geoJsonGeom) {
    const coordinates = geoJsonFeatureToOlFeature(geoJsonGeom).getGeometry().getCoordinates()

    return getOlGeometryByType(geoJsonGeom.type, coordinates)
  }

function geoJsonFeatureToOlFeature(geoJsonFeature) {
    return format.readFeature(geoJsonFeature, projectionOpts)
  }

function getOlGeometryByType(type, coordinateArray) {
    switch (type) {
      case 'Polygon':
        return new olGeomPolygon(coordinateArray)
      case 'LineString':
        return new olGeomLineString(coordinateArray)
      case 'MultiLineString':
        return new olGeomMultiLineString(coordinateArray)
      case 'Point':
        return new olGeomPoint(coordinateArray)
      case 'Circle':
        return new olGeomCircle(coordinateArray)
      case 'MultiPolygon':
        return new olGeomMultiPolygon(coordinateArray)
      case 'MultiPoint':
        return new olGeomMultiPoint(coordinateArray)
      default:
        return undefined
    }
  }


/**
 * Takes an array of vector features and creates a new merged geometry
 * @category LayerPanel
 * @function
 * @since 1.17.0
 * @param {Layer} VectorLayer - VectorLayer with features to be merged
 * @returns {Feature} olFeature
 */
export function mergeLayerFeatures (layer) {
  const features = layer.getSource().getFeatures()
  const firstFeature = features.shift()
  const { geometry: geoJsonGeom } = features.reduce((prevTarget, mergeTarget) => {
    const baseFeature = prevTarget
    const newGeom = getNewGeoJsonGeom(baseFeature, olFeatureToGeoJsonFeature(mergeTarget))
    return feature(newGeom)
  }, olFeatureToGeoJsonFeature(firstFeature))



  return geoJsonGeomToOlGeom(geoJsonGeom)
}