import { useEffect, useRef } from 'react';
import L from 'leaflet';
import 'leaflet-draw';
import { useMap } from 'react-leaflet';
import type { MapRectangle } from '../types';

interface DrawControlProps {
  color: string;
  rectangles: MapRectangle[];
  setRectangles: React.Dispatch<React.SetStateAction<MapRectangle[]>>;
  controlChange: (control: L.Control.Draw) => void;
}

export default function DrawControl({ color, rectangles, setRectangles, controlChange }: DrawControlProps) {
  const map = useMap();
  const drawControlRef = useRef<L.Control.Draw | null>(null);
  const editableLayerRef = useRef(new L.FeatureGroup());

  useEffect(() => {
    if (drawControlRef.current) {
      map.removeControl(drawControlRef.current);
    }

    const editableLayer = editableLayerRef.current;
    map.addLayer(editableLayer);

    const drawControl = new L.Control.Draw({
      draw: {
        polygon: false,
        polyline: false,
        rectangle: {},
        circle: false,
        circlemarker: false,
        marker: false,
      },
      edit: {
        featureGroup: editableLayer,
        remove: true,
      },
    });
    controlChange(drawControl);

    drawControlRef.current = drawControl;
    map.addControl(drawControl);

    map.on(L.Draw.Event.CREATED, handleDrawCreated);
    map.on(L.Draw.Event.EDITED, handleDrawEdited);
    map.on(L.Draw.Event.DELETED, handleDrawDeleted);

    return () => {
      if (drawControlRef.current) {
        map.removeControl(drawControlRef.current);
      }
      map.off(L.Draw.Event.CREATED, handleDrawCreated);
      map.off(L.Draw.Event.EDITED, handleDrawEdited);
      map.off(L.Draw.Event.DELETED, handleDrawDeleted);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [color, map, setRectangles]);

  const handleDrawCreated = (e: L.LeafletEvent) => {
    const event = e as L.DrawEvents.Created;
    const layer = event.layer;
    const bounds = (layer as L.Rectangle).getBounds();
    const newRectangle: MapRectangle = { layer, color, bounds };

    const isDuplicate = rectangles.some(
      (rectangle) => rectangle.bounds && (rectangle.bounds as L.LatLngBounds).equals?.(bounds)
    );

    if (!isDuplicate) {
      (layer as L.Path).setStyle({ color: color });
      setRectangles(prevRectangles => [...prevRectangles, newRectangle]);
      editableLayerRef.current.addLayer(layer);
    } else {
      layer.remove();
    }
  };

  const handleDrawEdited = (e: L.LeafletEvent) => {
    const event = e as L.DrawEvents.Edited;
    const layers = event.layers;
    layers.eachLayer((layer: L.Layer) => {
      setRectangles(prevRectangles =>
        prevRectangles.map(rectangle =>
          rectangle.layer === layer
            ? { ...rectangle, layer }
            : rectangle
        )
      );
    });
  };

  const handleDrawDeleted = (e: L.LeafletEvent) => {
    const event = e as L.DrawEvents.Deleted;
    const layers = event.layers;
    layers.eachLayer((layer: L.Layer) => {
      setRectangles(prevRectangles =>
        prevRectangles.filter(rectangle => rectangle.layer !== layer)
      );
    });
  };

  return null;
}
