import { LatLng, LatLngLiteral, Map, Polygon } from 'leaflet';
import { cloneDeep, keys, values } from 'lodash';
import { Ref, computed, ref } from 'vue';

const DEFAULT_COLORS = [
  '#FF0000', // Red
  '#00FF00', // Green
  '#0000FF', // Blue
  '#FFFF00', // Yellow
  '#FF00FF', // Magenta
  '#00FFFF', // Cyan
  '#FFA500', // Orange
  '#800080', // Purple
];

export function useMapPolygons(map: Ref<Map | null>) {
  const polygons = ref<Record<number, Polygon>>({});
  const currentPolygon = ref<Polygon | null>(null);
  const drawing = computed(() => !!currentPolygon.value);
  const _polygons = computed(() => {
    return values(polygons.value).map((polygon) => {
      const latlngs = (polygon.getLatLngs()[0] as any[]).map((latlng: LatLng) => ({
        lat: latlng.lat,
        lng: latlng.lng,
      }));

      return latlngs;
    });
  });

  const addPointToCurrentPolygon = ({ latlng }: { latlng: LatLng }) => {
    currentPolygon.value!.addLatLng(latlng);
  };

  const getDefaultColor = () => {
    const length = keys(polygons.value).length;
    return DEFAULT_COLORS[length % DEFAULT_COLORS.length];
  };

  const clearPolygons = () => {
    keys(polygons.value).forEach((key) => {
      const polygon = polygons.value[Number(key)];
      if (polygon) {
        map.value!.removeLayer(polygon);
      }
    });
    currentPolygon.value = null;
    polygons.value = {};
  };

  const getNewPolygon = (polygon?: LatLngLiteral[]) => {
    const color = getDefaultColor();
    return new Polygon(polygon || [], {
      color,
      fillColor: color,
      fillOpacity: 0.2,
      weight: 6,
    });
  };

  const setPolygons = (values: LatLngLiteral[][]) => {
    clearPolygons();
    values.forEach((polygon) => {
      const _polygon = getNewPolygon(polygon);
      _polygon.addTo(map.value!);
      const id = _polygon['_leaflet_id'];
      polygons.value[id] = _polygon;
    });
  };

  let mapCursor = 'default';

  const drawPolygon = (color?: string) => {
    mapCursor = map.value!.getContainer().style.cursor;
    map.value!.getContainer().style.cursor = 'crosshair';
    currentPolygon.value = getNewPolygon()
    currentPolygon.value.addTo(map.value!);
    map.value!.on('click', addPointToCurrentPolygon);
  };

  const finishPolygon = () => {
    map.value!.getContainer().style.cursor = mapCursor;
    const polygon = cloneDeep(currentPolygon.value);
    if (!polygon) return;
    if ((polygon.getLatLngs()[0] as any[]).length > 2) {
      const id = polygon['_leaflet_id'];
      polygons.value[id] = polygon as Polygon;
    }
    currentPolygon.value = null;
    map.value!.removeEventListener('click', addPointToCurrentPolygon);
  };

  return {
    drawPolygon,
    finishPolygon,
    clearPolygons,
    setPolygons,
    drawing,
    polygons: _polygons,
  };
}
