import { useYMaps } from "@pbe/react-yandex-maps";
import type {
  FC, ReactNode, PropsWithChildren,
} from "react";
import {
  memo,
  useContext,
  useEffect,
  useMemo,
  useRef,
} from "react";
import type { Clusterer } from "yandex-maps";
import { MapClusterer } from "./MapClusterer";
import type { TMapModulesProps } from "./MapModules";
import { MapModules } from "./MapModules";
import { MapPanel } from "./MapPanel";
import { MapPlacemark } from "./MapPlacemark";
import { mapDefaults } from "../config";
import type {
  IMap, TCluster, TMapContext, TPoint,
} from "../config/types";
import { MapContext } from "../context";
import { getActivePointsCount } from "../lib/clusterer";

export type TMapItemsProps = Pick<IMap, "clusters"> & PropsWithChildren<{
  onReady?: (clusters: Clusterer[]) => void;
}>;

const MemoModules = memo((props: TMapModulesProps): ReactNode => <MapModules {...props} />);
MemoModules.displayName = "MapModules";

const hasPointPaneData = (point: TPoint): boolean => {
  return !!(point?.meta?.pane?.title || point?.meta?.pane?.description);
};

/**
 * Внутренний компонент содержимого карт
 * @returns {ReactNode}
 */
const MapItems: FC<TMapItemsProps> = ({
  children,
  clusters = [],
  onReady,
}: TMapItemsProps): ReactNode => {

  const {
    panelSlot, modules, api,
  } = useContext<TMapContext>(MapContext);

  const ymaps = useYMaps(api?.load ?? mapDefaults.api!.load);

  const clustersRef = useRef<Clusterer[]>([]);

  const activePointsCountRef = useRef<number>(getActivePointsCount(clusters));

  const isPanelEnabled = useMemo(() => {
    if (panelSlot) {
      return true;
    }
    return clusters.some((cluster) => cluster.points.some((point) => hasPointPaneData(point)));
  }, [ panelSlot, clusters ]);

  useEffect(() => {
    clustersRef.current = [];
    activePointsCountRef.current = getActivePointsCount(clusters);
  }, [ clusters ]);

  const onClusterersReady = (instance: Clusterer) => {
    clustersRef.current.push(instance);
    if (clustersRef.current.length === clusters?.length && typeof onReady === "function") {
      onReady(clustersRef.current);
    }
  };

  return ymaps && (
    <>
      {clusters.map((cluster: TCluster, index) => {
        const { id, points } = cluster;
        const clusterKey = `clusterer_${id}_${points.map((point) => `${point.id}_${point.coords.join("_")}`).join("|")}_${index}`;
        return (
          <MapClusterer onReady={onClusterersReady} cluster={cluster} key={clusterKey}>
            {points.map((props: TPoint, index) => {
              const pointKey = `placemark_${id}_${props.id}_${props.coords.join("_")}_${index}`;
              return (
                <MapPlacemark cluster={cluster} activePointsCountRef={activePointsCountRef} isPanel={!!panelSlot || hasPointPaneData(props)} point={props} key={pointKey} />
              );
            })}
          </MapClusterer>
        );
      })}
      <MemoModules ymaps={ymaps} modules={modules} />
      {isPanelEnabled && <MapPanel>{panelSlot}</MapPanel>}
      {children}
    </>
  );

};

export {
  MapItems,
};
