import debounce from "lodash.debounce";
import maplibregl from "maplibre-gl";
import { useEffect, useMemo, useRef, useState } from "react";
import Map, { MapProvider } from "react-map-gl";
import { twMerge } from "tailwind-merge";
import { useOtherGroups, usePostamatesAndPvzGroups } from "../api.js";
import { MODE_TO_LAYER_VISIBILITY_MAPPER } from "../config";
import { icons } from "../icons/icons-config";
import { Sidebar } from "../modules/Sidebar/Sidebar";
import { TableWrapper } from "../modules/Table/TableWrapper";
import { SignOut } from "../SignOut";
import { useClickedPointConfig } from "../stores/useClickedPointConfig";
import { useLayersVisibility } from "../stores/useLayersVisibility";
import { useMode } from "../stores/useMode";
import {
  CATEGORIES_MAP,
  RANGE_FILTERS_KEYS,
  RANGE_FILTERS_MAP
} from "../stores/usePendingPointsFilters.js";
import { usePopup } from "../stores/usePopup";
import { useTable } from "../stores/useTable";
import { useUpdateLayerCounter } from "../stores/useUpdateLayerCounter.js";
import { getFilteredGroups, transliterate } from "../utils.js";
import { Basemap } from "./Basemap";
import { Header } from "./Header";
import { LastMLRun } from "./LastMLRun";
import { LAYER_IDS } from "./Layers/constants";
import { Layers } from "./Layers/Layers";
import { LayersControl } from "./LayersControl/LayersControl";
import { Legend } from "./Legend";
import { MapPopup } from "./Popup/Popup";
import { SidebarControl } from "./SidebarControl";

export const MapComponent = () => {
  const mapRef = useRef(null);
  const mapContainerRef = useRef(null);
  const sidebarRef = useRef(null);
  const { popup, setPopup } = usePopup();
  const { setClickedPointConfig } = useClickedPointConfig();
  const { setLayersVisibility } = useLayersVisibility();
  const { mode } = useMode();
  const { tableState, openTable } = useTable();
  const { toggleUpdatePVZLayer } = useUpdateLayerCounter();

  const { data: postamatesAndPvzGroups } = usePostamatesAndPvzGroups();
  const { data: otherGroups } = useOtherGroups();

  const filteredPostamatesGroups = useMemo(() => {
    return getFilteredGroups(postamatesAndPvzGroups);
  }, [postamatesAndPvzGroups]);

  const filteredOtherGroups = useMemo(() => {
    return getFilteredGroups(otherGroups);
  }, [otherGroups]);

  const mapIcons = useMemo(() => {
    const res = [];

    [...filteredOtherGroups, ...filteredPostamatesGroups].map((category) => {
      category.groups.map((group) => {
        res.push({name: transliterate(group.name + group.id), url: group.image});
      })
    });
    return [...res, ...icons];
  }, [icons, filteredPostamatesGroups, filteredOtherGroups]);

  useEffect(() => {
    mapIcons.map((icon) => {
      const img = new Image(
        icon.size?.width || 64,
        icon.size?.height || 64
      );
      img.src = icon.url;
      img.crossOrigin = "Anonymous";
      img.onload = () => {
        mapRef.current.addImage(icon.name, img);
        toggleUpdatePVZLayer();
      }
      img.src = icon.url;
      img.crossOrigin = "Anonymous";
    });
  }, [mapIcons]);

  const mapLayersIds = useMemo(() => {
    const res = []

    filteredPostamatesGroups.map((item) => {
      RANGE_FILTERS_MAP[`category${item.id}`] = {
        name: CATEGORIES_MAP[item.name],
      };
      item.groups.map((groupItem) => {
        if (!RANGE_FILTERS_KEYS.includes(`d${groupItem.id}`)) RANGE_FILTERS_KEYS.push(`d${groupItem.id}`);
        RANGE_FILTERS_MAP[`category${item.id}`][`d${groupItem.id}`] = groupItem.name;
        res.push(LAYER_IDS.pvz + groupItem.id);
      });
    });

    filteredOtherGroups.map((item) => {
      item.groups.map((groupItem) => {
        res.push(LAYER_IDS.other + groupItem.id);
      })
    });

    return res;
  }, [filteredPostamatesGroups, filteredOtherGroups]);

  useEffect(() => {
    setLayersVisibility(MODE_TO_LAYER_VISIBILITY_MAPPER[mode]);
    setPopup(null);
    setClickedPointConfig(null);
  }, [mode]);

  const handleClick = (event) => {
    if (!event.features) {
      setPopup(null);
      setClickedPointConfig(null);
      return;
    }

    const feature = event.features[0];
    if (!feature) {
      setPopup(null);
      setClickedPointConfig(null);
      return;
    }

    const { lng: pointLng } = event.lngLat;

    if (feature.geometry.type === "Point") {
      const coordinates = feature.geometry.coordinates.slice();
      while (Math.abs(pointLng - coordinates[0]) > 180) {
        coordinates[0] += pointLng > coordinates[0] ? 360 : -360;
      }

      setPopup({ features: event.features, coordinates });
    }
  };

  const handleMouseEnter = (event) => {
    const feature = event.features[0];
    if (!feature) return;

    mapRef.current.getCanvas().style.cursor = "pointer";
  };

  const handleMouseLeave = (event) => {
    const feature = event.features[0];
    if (!feature) {
      return;
    }
    mapRef.current.getCanvas().style.cursor = "";
  };

  useEffect(() => {
    const resizeObserver = new ResizeObserver(
      debounce(() => {
        mapRef?.current?.resize();
      }, 16)
    );
    if (mapContainerRef.current) {
      resizeObserver.observe(mapContainerRef.current);
    }

    return () => {
      resizeObserver.disconnect();
    };
  }, [mapContainerRef.current]);

  useEffect(() => {
    if (tableState.fullScreen && !tableState.isOpened) {
      openTable();
    }
  }, [tableState.fullScreen]);

  const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);

  const toggleCollapseSidebar = () =>
    setIsSidebarCollapsed((prevState) => !prevState);

  return (
    <MapProvider>
      <div className={"w-screen h-screen relative flex overflow-hidden"}>
        <Header />
        <Sidebar isCollapsed={isSidebarCollapsed} ref={sidebarRef} />
        <div className="flex-1 h-screen flex flex-col ">
          <div
            ref={mapContainerRef}
            className={twMerge(tableState.fullScreen ? "" : "flex-1")}
          >
            <Map
              mapLib={maplibregl}
              initialViewState={{
                latitude: 55.7558,
                longitude: 37.6173,
                zoom: 12,
              }}
              dragRotate={false}
              ref={mapRef}
              interactiveLayerIds={[
                LAYER_IDS["initial-match"],
                LAYER_IDS["initial-unmatch"],
                LAYER_IDS.approve,
                LAYER_IDS.working,
                LAYER_IDS.filteredWorking,
                LAYER_IDS.cancelled,
                ...mapLayersIds,
              ]}
              onClick={handleClick}
              onMouseEnter={handleMouseEnter}
              onMouseLeave={handleMouseLeave}
              id="map"
            >
              {popup && (
                <MapPopup
                  lat={popup.coordinates[1]}
                  lng={popup.coordinates[0]}
                  features={popup.features}
                  onClose={() => {
                    setPopup(null);
                    setClickedPointConfig(null);
                  }}
                />
              )}

              <SidebarControl toggleCollapse={toggleCollapseSidebar} />

              <Basemap />
              <Layers postGroups={filteredPostamatesGroups} otherGroups={filteredOtherGroups} />

              <Legend postGroups={filteredPostamatesGroups} otherGroups={filteredOtherGroups} />
              <LastMLRun />
              <SignOut />
              <LayersControl postGroups={filteredPostamatesGroups} otherGroups={filteredOtherGroups} />
            </Map>
          </div>
          <div className="w-full border-solid border-border border-0 border-t-[1px] z-20">
            <TableWrapper fullWidth={isSidebarCollapsed} />
          </div>
        </div>
      </div>
    </MapProvider>
  );
};
