import { MapContainer, TileLayer } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "./kartograf.scss";
import KartografControls from "./kartografControls";
import { useCallback, useEffect, useRef, useState } from "@wordpress/element";
import Supercluster from "supercluster";
import { subscribe, unsubscribe } from "../utils/events";
import _ from "lodash";
import EpakaApi from "./api/api";
import PointType from "../utils/pointsType";

import machine from "./img/machine.svg";
import point from "./img/point.svg";
import StringHelper from "../utils/stringHelper";
import { renderToStaticMarkup } from "react-dom/server";
import KartografSearch from "./kartografSearch";
import KartografPointsList from "./kartografPointsList";
import WindowWidthType from "../utils/windowWidthType";
import KartografDrawer from "./kartografDrawer";
import Div100vh from "react-div-100vh";
import KartografSplash from "./kartografSplash";
import KartografPointDetails from "./kartografPointDetails";

const countryCenterLatLngMap = new Map();
countryCenterLatLngMap.set("PL", new L.LatLng(51.9189046, 19.1343786));
countryCenterLatLngMap.set(
  "UA",
  new L.LatLng(49.0306652257167, 29.256591796875004),
);

const api = new EpakaApi();

const icons = {
  point: new L.Icon.Default({
    iconUrl: point,
    iconRetinaUrl: point,
    shadowUrl: "",
    shadowSize: [0, 0],
    iconSize: [48, 48],
    iconAnchor: [23, 39],
    popupAnchor: [48, 15],
  }),
  machine: new L.Icon.Default({
    iconUrl: machine,
    iconRetinaUrl: machine,
    shadowUrl: "",
    shadowSize: [0, 0],
    iconSize: [42, 28],
    iconAnchor: [21, 28],
    popupAnchor: [67, 15],
  }),
  point_selected: new L.Icon.Default({
    iconUrl: point,
    iconRetinaUrl: point,
    shadowUrl: "",
    shadowSize: [0, 0],
    iconSize: [45, 61],
    iconAnchor: [24, 52],
    popupAnchor: [48, 15],
  }),
  machine_selected: new L.Icon.Default({
    iconUrl: machine,
    iconRetinaUrl: machine,
    shadowUrl: "",
    shadowSize: [0, 0],
    iconSize: [67, 44],
    iconAnchor: [33, 44],
    popupAnchor: [67, 15],
  }),
};

const Kartograf = (props) => {
  const mapDivRef = useRef();
  const mapRef = useRef();
  const supercluster = useRef(
    new Supercluster({
      minZoom: 6,
      maxZoom: 18,
      radius: 120,
      log: true,
    }),
  );

  const markerLayerGroup = useRef();
  const clusterPolylineGroup = useRef();
  const locationPointGroup = useRef();

  const needToCheckIfPointsInViewport = useRef(false);
  const pointsFeaturesRef = useRef([]);
  const markersOnMap = useRef([]);
  const selectedMarkerRef = useRef();
  const selectedPoint = useRef();
  const selectedMarkerIdRef = useRef();
  const mapConfiguration = useRef();
  const initialMapCenter = useRef(countryCenterLatLngMap.get("PL"));
  const initialBounds = useRef();
  const initialZoom = useRef(7);
  const mapInitialized = useRef(false);

  const [isPointSelected, setIsPointSelected] = useState(false);
  const [IsPointsInViewport, setIsPointsInViewport] = useState(true);
  const [leafletReady, setLeafletReady] = useState(false);
  const [mapShow, setMapShow] = useState(false);
  const [visiblePointsFullData, setVisiblePointsFullData] = useState([]);
  const [pointLoading, setPointsLoading] = useState(false);

  const calculateWindowSize = (innerWidth) => {
    if (window.innerWidth >= WindowWidthType.LG) return WindowWidthType.LG;
    else if (window.innerWidth >= WindowWidthType.MD) return WindowWidthType.MD;
    else return WindowWidthType.SM;
  };

  const [windowSize, setWindowSize] = useState(
    calculateWindowSize(window.innerWidth),
  );

  const resizeObserver = new ResizeObserver(() => {
    if (mapRef.current) {
      mapRef.current.invalidateSize();
      setWindowSize(calculateWindowSize(window.innerWidth));
    }
  });

  const paddingMap = {
    paddingTop: 100, //windowSize === WindowWidthType.SM ? 75 : 100,
    paddingBottom: windowSize === WindowWidthType.SM ? 60 : 20,
    paddingLeft: windowSize === WindowWidthType.SM ? 20 : 400,
    paddingRight: windowSize === WindowWidthType.SM ? 20 : 100,
  };

  const getIcon = (feature, type, isSelectedMarker) => {
    switch (type) {
      case PointType.Point:
        return isSelectedMarker ? icons["point_selected"] : icons["point"];
      case PointType.Machine:
        return isSelectedMarker ? icons["machine_selected"] : icons["machine"];
      case PointType.PointAndEpaka:
        return isSelectedMarker ? icons["point_selected"] : icons["point"];
      case PointType.Epaka:
        return isSelectedMarker ? icons["point_selected"] : icons["point"];
      default:
        return new L.DivIcon({
          className: "",
          html: `<div class="circle"><div class="innerCircle"><span>${feature.properties.point_count}</span></div></div>`,
        });
    }
  };

  const generateNewMarker = (feature, clickHandler, type, isSelectedMarker) => {
    let icon = getIcon(feature, type, isSelectedMarker);

    const marker = new L.Marker(
      [feature.geometry.coordinates[1], feature.geometry.coordinates[0]],
      {
        icon: icon,
        title: feature.id,
        pointType: type,
        isCluster: feature.properties.cluster ?? false,
      },
    );

    return marker.on("click", clickHandler);
  };

  const onPointApproval = () => {
    mapConfiguration.current.onPointApproval(selectedPoint.current);
    closeMap();
  };

  const init = useCallback(async () => {
    if (
      mapConfiguration.current.courier === 30 ||
      mapConfiguration.current.courier === 31 ||
      mapConfiguration.current.courier === 43
    ) {
      let center;
      let zoom;
      try {
        center = mapRef.current.getCenter();
        zoom = mapRef.current.getZoom();
      } catch (e) {
        center = L.latLng(51.9189046, 19.1343786);
        zoom = 16;
      }
      const response = await api.getPointsFromFile(
        mapConfiguration.current.courier,
        mapConfiguration.current.country,
        [center.lat, center.lng],
        mapConfiguration.current.options,
      );

      if (_.isArray(response)) {
        let pointsFeatureArray = {
          type: "FeatureCollection",
          features: [],
        };

        for (let i = 0; i < response.length; i++) {
          const pointFeature = {
            type: "Feature",
            geometry: {
              coordinates: [response[i].lon, response[i].lat],
            },
            id: response[i].point_id,
            properties: {
              point_id: response[i].point_id,
              point_type: response[i].type,
            },
          };

          pointsFeatureArray.features.push(pointFeature);
        }
        pointsFeaturesRef.current = pointsFeatureArray.features;
        supercluster.current.load(pointsFeatureArray.features);

        const bounds = mapRef.current.getBounds();
        const bbox = [
          bounds.getWest(),
          bounds.getSouth(),
          bounds.getEast(),
          bounds.getNorth(),
        ];
        const zoom = mapRef.current.getZoom();
        const clusters = supercluster.current.getClusters(bbox, zoom);

        createMarkers(clusters, response).then(() => {
          if (selectedMarkerRef.current) {
            selectedMarkerRef.current.openPopup();
            const elems = document.querySelectorAll("button.selectPoint");
            elems.forEach((elem) => {
              if (!!elem) elem.addEventListener("click", onPointApproval);
            });
          }
        });
      }
    } else {
      const response = await api.getPointsFromFile(
        mapConfiguration.current.courier,
        mapConfiguration.current.country,
        selectedMarkerIdRef.current,
        mapConfiguration.current.options,
      );

      if (_.isArray(response)) {
        let pointsFeatureArray = {
          type: "FeatureCollection",
          features: [],
        };

        for (let i = 0; i < response.length; i++) {
          const pointFeature = {
            type: "Feature",
            geometry: {
              coordinates: [response[i].lon, response[i].lat],
            },
            id: response[i].point_id,
            properties: {
              point_id: response[i].point_id,
              point_type: response[i].type,
            },
          };

          pointsFeatureArray.features.push(pointFeature);
        }
        pointsFeaturesRef.current = pointsFeatureArray.features;
        supercluster.current.load(pointsFeatureArray.features);

        const bounds = mapRef.current.getBounds();
        const bbox = [
          bounds.getWest(),
          bounds.getSouth(),
          bounds.getEast(),
          bounds.getNorth(),
        ];
        const zoom = mapRef.current.getZoom();
        const clusters = supercluster.current.getClusters(bbox, zoom);
        createMarkers(clusters, undefined).then(() => {
          if (selectedMarkerRef.current) {
            selectedMarkerRef.current.openPopup();
            const elems = document.querySelectorAll("button.selectPoint");
            elems.forEach((elem) => {
              if (!!elem) elem.addEventListener("click", onPointApproval);
            });
          }
        });
      }
    }
  }, []);

  const onPointClick = useCallback(
    (point) => {
      if (selectedMarkerRef.current) {
        selectedMarkerRef.current.closePopup();
      }
      if (point.geometry) {
        selectedMarkerIdRef.current = point.properties.point_id;
        mapRef.current.flyTo(
          [point.geometry.coordinates[1], point.geometry.coordinates[0]],
          18,
          { duration: 0.5 },
        );
      }
      if (point.lat) {
        selectedMarkerIdRef.current = point.point_id;
        mapRef.current.flyTo([point.lat, point.lon], 18, { duration: 0.5 });
      }
    },
    [markersOnMap.current],
  );

  const spiderify = (features, cluster) => {
    const markersWithoutCluster = markersOnMap.current.filter(
      (elem) => elem.options.title !== cluster.options.title,
    );

    //Increase to increase the distance away that spiderfied markers appear from the center

    const leavesSeparation = 0.00015;
    const theta = (Math.PI * 2) / features.length;

    let markersToAdd = [];
    let polyLines = [];
    let angle = theta;
    for (let i = 0; i < features.length; i++) {
      angle = theta * i;
      //lng
      features[i].geometry.coordinates[0] =
        cluster.getLatLng().lng + leavesSeparation * Math.sin(angle);
      //lat
      features[i].geometry.coordinates[1] =
        cluster.getLatLng().lat + leavesSeparation * Math.cos(angle);

      const isSelectedMarker = features[i].id === selectedMarkerIdRef.current;
      const generatedMarker = generateNewMarker(
        features[i],
        () => {
          onPointClick(features[i]);
        },
        features[i].properties.point_type,
        isSelectedMarker,
      );
      markersWithoutCluster.push(generatedMarker);
      markersToAdd.push(generatedMarker);
      polyLines.push(
        new L.Polyline(
          [
            [cluster.getLatLng().lat, cluster.getLatLng().lng],
            [
              features[i].geometry.coordinates[1],
              features[i].geometry.coordinates[0],
            ],
          ],
          {
            color: "black",
            weight: 1,
            opacity: 0.5,
            smoothFactor: 1,
          },
        ),
      );
    }
    console.log(markersWithoutCluster);
    return {
      newMarkersArray: markersWithoutCluster,
      markersToAdd: markersToAdd,
      polylines: polyLines,
    };
  };

  const onClusterClickSpiderify = useCallback(
    (clusterMarker) => {
      const childrenOfCluster = supercluster.current.getChildren(
        clusterMarker.options.title,
      );

      const result = spiderify(childrenOfCluster, clusterMarker);

      markerLayerGroup.current.removeLayer(clusterMarker);

      result.markersToAdd.forEach((marker) => {
        markerLayerGroup.current.addLayer(marker);
      });

      if (!clusterPolylineGroup.current) {
        clusterPolylineGroup.current = new L.LayerGroup();
        mapRef.current.addLayer(clusterPolylineGroup.current);
      }
      result.polylines.forEach((polyline) =>
        clusterPolylineGroup.current.addLayer(polyline),
      );
    },
    [clusterPolylineGroup.current, markerLayerGroup.current],
  );

  const createMarkers = useCallback(
    async (points, fullPoints) => {
      setPointsLoading(true);
      if (!markerLayerGroup.current) {
        markerLayerGroup.current = new L.LayerGroup();
        mapRef.current.addLayer(markerLayerGroup.current);
      }
      let markersToAdd = [];
      let markersToRemove = [];
      let markersAlreadyExisting = [];

      let markersForceRemove = [];

      if (markersOnMap.current.length === 0) {
        for (let i = 0; i < points.length; i++) {
          const isSelectedMarker = points[i].id === selectedMarkerIdRef.current;
          if (points[i].properties.cluster) {
            const newMarkerCluster = generateNewMarker(
              points[i],
              () => {
                if (mapRef.current.getZoom() < 18) {
                  mapRef.current.flyTo(
                    [
                      points[i].geometry.coordinates[1],
                      points[i].geometry.coordinates[0],
                    ],
                    mapRef.current.getZoom() + 1,
                  );
                } else {
                  onClusterClickSpiderify(newMarkerCluster);
                }
              },
              "cluster",
              isSelectedMarker,
            );
            markersToAdd.push(newMarkerCluster);
          } else {
            markersToAdd.push(
              generateNewMarker(
                points[i],
                () => {
                  onPointClick(points[i]);
                },
                points[i].properties.point_type,
                isSelectedMarker,
              ),
            );
          }
        }
      } else {
        for (let i = 0; i < points.length; i++) {
          const isSelectedMarker = points[i].id === selectedMarkerIdRef.current;
          const markerAlreadyExists = markerLayerGroup.current
            .getLayers()
            .filter((elem) => elem.options.title === points[i].id)
            .pop();

          if (markerAlreadyExists) {
            if (isSelectedMarker) {
              if (
                markerAlreadyExists.options.icon.options.iconSize[0] ===
                  icons["machine_selected"].options.iconSize[0] ||
                markerAlreadyExists.options.icon.options.iconSize[1] ===
                  icons["point_selected"].options.iconSize[1]
              ) {
                markersAlreadyExisting.push(markerAlreadyExists);
              } else {
                let icon = getIcon(
                  points[i],
                  points[i].properties.point_type,
                  isSelectedMarker,
                );
                markerAlreadyExists.setIcon(icon);
                markersAlreadyExisting.push(markerAlreadyExists);
              }
            } else {
              if (
                markerAlreadyExists.options.icon.options.iconSize[0] ===
                  icons["machine_selected"].options.iconSize[0] ||
                markerAlreadyExists.options.icon.options.iconSize[1] ===
                  icons["point_selected"].options.iconSize[1]
              ) {
                let icon = getIcon(
                  points[i],
                  points[i].properties.point_type,
                  isSelectedMarker,
                );
                markerAlreadyExists.setIcon(icon);
                markersAlreadyExisting.push(markerAlreadyExists);
              } else {
                markersAlreadyExisting.push(markerAlreadyExists);
              }
            }
          } else {
            if (points[i].properties.cluster) {
              const newMarkerCluster = generateNewMarker(
                points[i],
                () => {
                  if (mapRef.current.getZoom() < 18) {
                    mapRef.current.flyTo(
                      [
                        points[i].geometry.coordinates[1],
                        points[i].geometry.coordinates[0],
                      ],
                      mapRef.current.getZoom() + 1,
                    );
                  } else {
                    onClusterClickSpiderify(newMarkerCluster);
                  }
                },
                "cluster",
                isSelectedMarker,
              );
              markersToAdd.push(newMarkerCluster);
            } else {
              markersToAdd.push(
                generateNewMarker(
                  points[i],
                  () => {
                    onPointClick(points[i]);
                  },
                  points[i].properties.point_type,
                  isSelectedMarker,
                ),
              );
            }
          }
        }
        markersToRemove = markerLayerGroup.current
          .getLayers()
          .filter(
            (layer) =>
              markersToAdd
                .concat(markersAlreadyExisting)
                .filter(
                  (marker) => layer.options.title === marker.options.title,
                ).length === 0,
          );
      }

      markersOnMap.current = markersToAdd.concat(markersAlreadyExisting);

      if (
        selectedMarkerIdRef.current &&
        mapRef.current.getZoom() === 18 &&
        markerLayerGroup.current
      ) {
        if (!clusterPolylineGroup.current) {
          clusterPolylineGroup.current = new L.LayerGroup();
          mapRef.current.addLayer(clusterPolylineGroup.current);
        }
        for (let i = 0; i < markersOnMap.current.length; i++) {
          if (markersOnMap.current[i].options.isCluster) {
            const childrenOfCluster = supercluster.current.getChildren(
              markersOnMap.current[i].options.title,
            );
            const selectedMarkerFoundInCluster = childrenOfCluster.filter(
              (elem) => elem.id === selectedMarkerIdRef.current,
            );
            if (selectedMarkerFoundInCluster.length > 0) {
              const markersAlreadyExisting = markerLayerGroup.current
                .getLayers()
                .filter(
                  (elem) =>
                    childrenOfCluster.filter(
                      (child) => child.id === elem.options.title,
                    ).length > 0,
                );
              markersToRemove = markersToRemove.filter(
                (elem) =>
                  childrenOfCluster.filter(
                    (child) => child.id === elem.options.title,
                  ).length === 0,
              );

              if (markersAlreadyExisting.length === 0) {
                const result = spiderify(
                  childrenOfCluster,
                  markersOnMap.current[i],
                );
                markersToAdd = markersToAdd.filter(
                  (elem) =>
                    elem.options.title !==
                    markersOnMap.current[i].options.title,
                );
                markersToRemove.push(markersOnMap.current[i]);
                markersOnMap.current = result.newMarkersArray;
                markersToAdd = markersToAdd.concat(result.markersToAdd);
                result.polylines.forEach((polyline) =>
                  clusterPolylineGroup.current.addLayer(polyline),
                );
              } else {
                markersToAdd = markersToAdd.filter(
                  (elem) =>
                    elem.options.title !==
                    markersOnMap.current[i].options.title,
                );
                markersOnMap.current = markersOnMap.current.concat(
                  markersAlreadyExisting,
                );
                markersToRemove.push(markersOnMap.current[i]);
              }
            } else {
              clusterPolylineGroup.current.clearLayers();
            }
          }
        }
      } else {
        if (markerLayerGroup.current) {
          if (clusterPolylineGroup.current) {
            clusterPolylineGroup.current.clearLayers();
          }
          for (let i = 0; i < markersOnMap.current.length; i++) {
            if (markersOnMap.current[i].options.isCluster) {
              const childrenOfCluster = supercluster.current.getChildren(
                markersOnMap.current[i].options.title,
              );
              const markersAlreadyExisting = markerLayerGroup.current
                .getLayers()
                .filter(
                  (elem) =>
                    childrenOfCluster.filter(
                      (child) => child.id === elem.options.title,
                    ).length > 0,
                );
              markersToRemove = markersToRemove.concat(markersAlreadyExisting);
            }
          }
        }
      }

      markersToRemove = markersToRemove.concat(markersForceRemove);

      markersToRemove.forEach((marker) => {
        markerLayerGroup.current.removeLayer(marker);
      });

      markersToAdd.forEach((marker) => {
        markerLayerGroup.current.addLayer(marker);
      });

      if (typeof fullPoints === "undefined") {
        const response = await api.getFullPointsDataByLatLngProximity(
          mapConfiguration.current.courier,
          mapConfiguration.current.country,
          mapRef.current.getCenter(),
          mapConfiguration.current.options,
          selectedMarkerIdRef.current,
        );
        fullPoints = response.points;
      }

      for (let i = 0; i < fullPoints.length; i++) {
        for (let j = 0; j < markersOnMap.current.length; j++) {
          if (
            fullPoints[i].point_id === markersOnMap.current[j].options.title
          ) {
            if (
              markersOnMap.current[j].getPopup() &&
              windowSize === WindowWidthType.SM
            ) {
              markersOnMap.current[j].closePopup();
              markersOnMap.current[j].unbindPopup();
            }
            if (
              !markersOnMap.current[j].getPopup() &&
              windowSize !== WindowWidthType.SM
            ) {
              const isChosenPoint =
                mapConfiguration.current.chosenPointId ===
                markersOnMap.current[j].options.title;

              let button = (
                <button
                  className={
                    "epakaBtn " +
                    (isChosenPoint ? "bg-green" : "") +
                    " selectPoint epaka-d-flex align-items-center justify-content-center"
                  }
                  onClick={() => {
                    mapConfiguration.current.onPointApproval(fullPoints[i]);
                  }}
                >
                  <span className={"label"}>
                    {isChosenPoint
                      ? "currently-selected-point"
                      : "Wybierz ten punkt"}
                  </span>
                  <i
                    className={
                      "epaka-icons icon-chevron_right_2nd text-white font-size-12px"
                    }
                    style={{ right: "1rem" }}
                  />
                </button>
              );

              let popup = new L.Popup().setContent(
                StringHelper.preparePointDescriptionToPopup(fullPoints[i]) +
                  renderToStaticMarkup(button),
              );

              markersOnMap.current[j].bindPopup(popup, {
                className: "popup",
                closeButton: false,
                closeOnClick: false,
                interactive: false,
                autoPan: false,
              });
            }
            if (
              markersOnMap.current[j].options.title ===
              selectedMarkerIdRef.current
            ) {
              selectedMarkerRef.current = markersOnMap.current[j];
              selectedPoint.current = fullPoints[i];
              setIsPointSelected(true);
            }
          }
        }
        fullPoints[i].clickHandler = () => {
          onPointClick(fullPoints[i]);
        };
      }

      setVisiblePointsFullData(fullPoints);
      setPointsLoading(false);
    },
    [
      markersOnMap.current,
      mapRef.current,
      selectedMarkerIdRef.current,
      markerLayerGroup.current,
      windowSize,
    ],
  );

  const onMoveEndHandler = useCallback(
    async (event) => {
      if (
        mapConfiguration.current.courier === 30 ||
        mapConfiguration.current.courier === 31 ||
        mapConfiguration.current.courier === 43
      ) {
        let center;
        try {
          center = mapRef.current.getCenter();
        } catch (e) {
          center = L.latLng(51.9189046, 19.1343786);
        }
        const response = await api.getPointsFromFile(
          mapConfiguration.current.courier,
          mapConfiguration.current.country,
          [center.lat, center.lng],
          mapConfiguration.current.options,
        );

        if (_.isArray(response)) {
          let pointsFeatureArray = {
            type: "FeatureCollection",
            features: [],
          };

          for (let i = 0; i < response.length; i++) {
            const pointFeature = {
              type: "Feature",
              geometry: {
                coordinates: [response[i].lon, response[i].lat],
              },
              id: response[i].point_id,
              properties: {
                point_id: response[i].point_id,
                point_type: response[i].type,
              },
            };

            pointsFeatureArray.features.push(pointFeature);
          }
          pointsFeaturesRef.current = pointsFeatureArray.features;
          supercluster.current.load(pointsFeatureArray.features);

          const bounds = event.target.getBounds();
          const bbox = [
            bounds.getWest(),
            bounds.getSouth(),
            bounds.getEast(),
            bounds.getNorth(),
          ];
          const zoom = event.target.getZoom();
          debugger;
          const clusters = supercluster.current.getClusters(bbox, zoom);

          createMarkers(clusters, response).then(() => {
            if (selectedMarkerRef.current) {
              selectedMarkerRef.current.openPopup();
              const elems = document.querySelectorAll("button.selectPoint");
              elems.forEach((elem) => {
                if (!!elem) elem.addEventListener("click", onPointApproval);
              });
            }
          });
        }
      } else {
        const bounds = event.target.getBounds();
        const bbox = [
          bounds.getWest(),
          bounds.getSouth(),
          bounds.getEast(),
          bounds.getNorth(),
        ];
        const zoom = event.target.getZoom();
        const clusters = supercluster.current.getClusters(bbox, zoom);

        createMarkers(clusters, undefined).then(() => {
          if (selectedMarkerRef.current) {
            selectedMarkerRef.current.openPopup();
            const elems = document.querySelectorAll("button.selectPoint");
            elems.forEach((elem) => {
              if (!!elem) elem.addEventListener("click", onPointApproval);
            });
          }
        });

        if (needToCheckIfPointsInViewport.current) {
          needToCheckIfPointsInViewport.current = false;
          checkIfAnyPointInViewport();
        }
      }
    },
    [mapRef.current, supercluster.current],
  );

  const checkIfAnyPointInViewport = useCallback(() => {
    if (mapRef.current && markerLayerGroup.current && initialBounds.current) {
      const mapViewportBounds = mapRef.current.getBounds();
      const mapViewportCenter = mapViewportBounds.getCenter();
      const isAnyPointInView = markerLayerGroup.current.getLayers().length > 0;

      setIsPointsInViewport(isAnyPointInView);
      if (!isAnyPointInView) {
        let closestPointLatLng = null;
        let minDistance = Infinity;
        pointsFeaturesRef.current.forEach((feature) => {
          const pointLatLng = new L.LatLng(
            feature.geometry.coordinates[1],
            feature.geometry.coordinates[0],
          );
          const distance = pointLatLng.distanceTo(mapViewportCenter);
          if (minDistance > distance) {
            minDistance = distance;
            closestPointLatLng = pointLatLng;
          }
        });

        const bounds = new L.LatLngBounds(
          mapViewportCenter,
          closestPointLatLng,
        );

        const userLocationMarkerIcon = new L.DivIcon({
          className: "userLocationMarkerWrapper",
          html: `<img class="userLocationMarker" src="${gps}" alt="location"/>`,
          iconSize: [24, 24],
          iconAnchor: [12, 12],
        });

        if (!locationPointGroup.current) {
          locationPointGroup.current = new L.LayerGroup();
          mapRef.current.addLayer(locationPointGroup.current);
        } else {
          locationPointGroup.current.clearLayers();
        }
        locationPointGroup.current.addLayer(
          L.marker(mapViewportCenter, {
            icon: userLocationMarkerIcon,
          }),
        );

        mapRef.current.fitBounds(bounds, {
          paddingTopLeft: new L.Point(
            paddingMap.paddingLeft,
            paddingMap.paddingTop,
          ),
          paddingBottomRight: new L.Point(
            paddingMap.paddingRight,
            paddingMap.paddingBottom,
          ),
        });
      }
    }
  }, [mapRef.current, markerLayerGroup.current]);

  const openEpakaMapListener = useCallback(
    (data) => {
      document.body.style.overflowY = "hidden";
      if ("virtualKeyboard" in navigator) {
        navigator.virtualKeyboard.hide();
      }
      mapConfiguration.current = data.detail;

      console.log(mapConfiguration.current);
      if (mapConfiguration.current.chosenPoint) {
        selectedMarkerIdRef.current =
          mapConfiguration.current.chosenPoint.point_id;
        initialMapCenter.current = new L.LatLng(
          mapConfiguration.current.chosenPoint.lat,
          mapConfiguration.current.chosenPoint.lon,
        );
        initialZoom.current = 18;
        setMapShow(true);
      } else {
        if (
          mapConfiguration.current.postal_code &&
          mapConfiguration.current.country
        ) {
          api
            .getNominatimSearch(
              mapConfiguration.current.postal_code,
              mapConfiguration.current.country,
              1,
            )
            .then((response) => {
              if (response.length > 0) {
                initialBounds.current = response[0].boundingBox ?? null;
                if (response[0].lat && response[0].lon) {
                  initialMapCenter.current = new L.LatLng(
                    response[0].lat,
                    response[0].lon,
                  );
                }
                initialZoom.current = 14;
              } else {
                initialBounds.current = undefined;
                initialMapCenter.current = new L.LatLng(52, 20);
                initialZoom.current = 14;
              }
              setMapShow(true);
            });
        } else {
          if (mapConfiguration.current.country) {
            // initialMapCenter.current = countryCenterLatLngMap.get('UA');
            api
              .getNominatimSearch(
                mapConfiguration.current.country,
                mapConfiguration.current.country,
                1,
              )
              .then((response) => {
                if (response.length > 0) {
                  initialBounds.current = response[0].boundingBox ?? null;
                  if (response[0].lat && response[0].lon) {
                    initialMapCenter.current = new L.LatLng(
                      response[0].lat,
                      response[0].lon,
                    );
                  }
                  initialZoom.current = 7;
                } else {
                  initialBounds.current = undefined;
                  initialMapCenter.current = new L.LatLng(52, 20);
                  initialZoom.current = 7;
                }
                setMapShow(true);
              });
          } else {
            initialMapCenter.current = countryCenterLatLngMap["PL"];
            initialBounds.current = null;
            initialZoom.current = 7;
            setMapShow(true);
          }
        }
      }
    },
    [mapRef.current, windowSize],
  );

  // useEffect(() => {
  //   if (mapDivRef.current && mapRef.current) {
  //     const resizeObserver = new ResizeObserver(() => {
  //       if (mapRef.current) {
  //         mapRef.current.invalidateSize();
  //       }
  //     });
  //     resizeObserver.observe(mapDivRef.current);
  //     return () => {
  //       if (mapDivRef.current) {
  //         resizeObserver.unobserve(mapDivRef.current);
  //       }
  //     };
  //   }
  // }, [mapRef.current]);

  const closeMap = () => {
    document.body.style.overflowY = "scroll";
    // if(splashRef.current && splashRef.current.exitFullscreen)
    if (document.fullscreenEnabled && document.fullscreenElement !== null) {
      document.exitFullscreen();
    }
    setMapShow(false);
    setLeafletReady(false);
    setVisiblePointsFullData([]);
    mapInitialized.current = false;
    markerLayerGroup.current = undefined;
    clusterPolylineGroup.current = undefined;
    locationPointGroup.current = undefined;
    markersOnMap.current = [];
    selectedMarkerIdRef.current = undefined;
    selectedPoint.current = undefined;
    setIsPointSelected(false);
  };

  useEffect(() => {
    if (mapRef.current && !mapInitialized.current) {
      if (leafletReady) {
        init().then(() => {
          mapInitialized.current = true;
          mapRef.current.on("moveend", onMoveEndHandler);
          resizeObserver.unobserve(mapRef.current.getContainer());
          resizeObserver.observe(mapRef.current.getContainer());
          checkIfAnyPointInViewport();
        });
      }
    }
  }, [leafletReady]);

  useEffect(() => {
    subscribe("openEpakaMap", openEpakaMapListener);
    return () => {
      unsubscribe("openEpakaMap", openEpakaMapListener);
    };
  }, [mapRef.current]);

  return (
    <div>
      {mapShow && (
        <KartografSplash show={mapShow}>
          <Div100vh className={"epaka-d-flex epaka-flex-column"}>
            <KartografSearch
              label={"Wpisz adres lub numer Punktu"}
              windowSize={windowSize}
              closeMap={() => {
                closeMap();
              }}
              country={mapConfiguration.current.country}
              courier={mapConfiguration.current.courier}
              onListPositionClick={(item) => {
                if (item.point_id) {
                  selectedMarkerIdRef.current = item.point_id;
                  mapRef.current.flyTo([item.lat, item.lon], 18, {
                    duration: 0.5,
                  });
                } else {
                  mapRef.current.flyToBounds(item.boundingBox, {
                    duration: 0.5,
                  });
                  needToCheckIfPointsInViewport.current = true;
                }
              }}
              results={
                visiblePointsFullData && visiblePointsFullData.length > 0 ? (
                  <KartografPointsList
                    loading={pointLoading}
                    markersInView={IsPointsInViewport}
                    showIcons={true}
                    // showFilters={
                    //   (mapConfiguration.current.courier === 12 ||
                    //     mapConfiguration.current.courier === 6) &&
                    //   !mapConfiguration.current.options.blockParcelLocker
                    // }
                    // filters={{
                    //   showPoints: mapConfiguration.current.options.showPoints,
                    //   showMachines: mapConfiguration.current.options.showMachines,
                    // }}
                    // onFilterChange={(showPoints, showMachines) => {
                    //   mapConfiguration.current.options.showPoints = showPoints;
                    //   mapConfiguration.current.options.showMachines = showMachines;
                    //   init();
                    // }}
                    points={visiblePointsFullData}
                    selectedPointId={selectedMarkerIdRef.current}
                  />
                ) : null
              }
            />
            <div ref={mapDivRef} className={"mapArea"}>
              <MapContainer
                ref={mapRef}
                center={initialMapCenter.current}
                bounds={initialBounds.current}
                zoom={initialZoom.current}
                minZoom={6}
                maxZoom={18}
                className={"epaka-pl-leaflet-map-container"}
                scrollWheelZoom={true}
                whenReady={() => {
                  setLeafletReady(true);
                }}
                zoomControl={false}
              >
                <KartografControls onMapClose={closeMap} />
                <TileLayer
                  attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                  url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                />
              </MapContainer>
            </div>

            {windowSize === WindowWidthType.SM && (
              <KartografDrawer autosize={selectedPoint.current !== null}>
                {selectedPoint.current ? (
                  <KartografPointDetails
                    point={selectedPoint.current}
                    onCancel={() => {
                      selectedMarkerRef.current.closePopup();
                      selectedMarkerRef.current = undefined;
                      selectedMarkerIdRef.current = undefined;
                      selectedPoint.current = undefined;
                      setIsPointSelected(false);
                    }}
                    onClick={() => {
                      onPointApproval();
                    }}
                  />
                ) : (
                  <KartografPointsList
                    showIcons={true}
                    showMobile={true}
                    // showFilters={
                    //   (mapConfiguration.current.courier === 12 ||
                    //     mapConfiguration.current.courier === 6) &&
                    //   !mapConfiguration.current.options.blockParcelLocker
                    // }
                    // filters={{
                    //   showPoints: mapConfiguration.current.options.showPoints,
                    //   showMachines: mapConfiguration.current.options.showMachines,
                    // }}
                    // onFilterChange={(showPoints, showMachines) => {
                    //   mapConfiguration.current.options.showPoints = showPoints;
                    //   mapConfiguration.current.options.showMachines = showMachines;
                    //   init();
                    // }}
                    points={visiblePointsFullData}
                    selectedPointId={selectedMarkerIdRef.current}
                  />
                )}
              </KartografDrawer>
            )}
          </Div100vh>
        </KartografSplash>
      )}
    </div>
  );
};

export default Kartograf;
