import { useEffect } from "preact/hooks";

import { LNP_LINE_ID_PROP } from "../utils/constants";
import useMapContext from "../utils/hooks/useMapContext";

/**
 * This component defines the behavior when user select or hover a queryable feature
 */
function FeaturesInfosListener() {
  const {
    baseLayer,
    featuresInfos,
    featuresInfosHovered,
    linesNetworkPlanLayer,
    notificationsLayer,
    realtimeLayer,
    setLinesIds,
    setSelectedFeature,
    setSelectedFeatures,
    setStationId,
    setTrainId,
    stationsLayer,
    tenant,
  } = useMapContext();

  useEffect(() => {
    // We want to call this use effect only when a hover happened
    // and a query has been done not when the component is mounted
    if (!featuresInfosHovered?.length) {
      return;
    }
    const [realtimeFeature] =
      featuresInfosHovered?.find((info) => {
        return info.layer === realtimeLayer;
      })?.features || [];

    const [notificationFeature] =
      featuresInfosHovered?.find((info) => {
        return info.layer === notificationsLayer;
      })?.features || [];

    // We prioritize only symbol notifications, because we want to be able to click on trains on lines
    const isSymbolNotification =
      notificationFeature?.getGeometry()?.getType() === "Point";

    const priorityFeature = isSymbolNotification
      ? notificationFeature || realtimeFeature
      : realtimeFeature || notificationFeature;

    if (priorityFeature === realtimeFeature) {
      realtimeLayer?.highlight(realtimeFeature);
    } else {
      realtimeLayer?.highlight(null);
    }
  }, [featuresInfosHovered, notificationsLayer, realtimeLayer]);

  useEffect(() => {
    // We want to call this use effect only when a click happened
    // and a query has been done not when the component is mounted
    if (!featuresInfos?.length) {
      // Reinitialize selected features
      setSelectedFeature(null);
      setSelectedFeatures([]);
      return;
    }

    const [realtimeFeature] =
      featuresInfos?.find((info) => {
        return info.layer === realtimeLayer;
      })?.features || [];

    const [notificationFeature] =
      featuresInfos?.find((info) => {
        return info.layer === notificationsLayer;
      })?.features || [];

    const [stationFeature] =
      featuresInfos?.find((info) => {
        return info.layer === stationsLayer;
      })?.features || [];

    // Find the line to highlight in the LNP layer
    const linesFeatures =
      featuresInfos?.find((featuresInfo) => {
        return featuresInfo.layer === linesNetworkPlanLayer;
      })?.features || [];

    const linesIds = [
      ...new Set(
        (linesFeatures || []).map((f) => {
          return f.get(LNP_LINE_ID_PROP) as string;
        }),
      ),
    ];

    const features =
      featuresInfos?.flatMap((info) => {
        return info.features;
      }) || [];

    // We prioritize only symbol notifications, because we want to be able to click on trains on lines
    const isSymbolNotification =
      notificationFeature?.getGeometry()?.getType() === "Point";

    let priorityFeature = isSymbolNotification
      ? notificationFeature || realtimeFeature
      : realtimeFeature || notificationFeature;

    priorityFeature = priorityFeature || stationFeature;

    // TODO this if/else must be refactored. We should not have to do setLinesIds here
    if (priorityFeature) {
      setSelectedFeature(priorityFeature);
      setSelectedFeatures([priorityFeature]);
      setLinesIds(null);
    } else if (!features.length) {
      setSelectedFeature(null);
      setSelectedFeatures([]);
      setLinesIds(null);
    } else {
      setSelectedFeatures(features);
      setSelectedFeature(features[0]);
      setLinesIds(linesIds?.length ? linesIds : null);
    }
  }, [
    baseLayer?.mapLibreMap,
    featuresInfos,
    linesNetworkPlanLayer,
    realtimeLayer,
    notificationsLayer,
    setLinesIds,
    setSelectedFeature,
    setSelectedFeatures,
    setStationId,
    setTrainId,
    stationsLayer,
    tenant,
  ]);

  return null;
}
export default FeaturesInfosListener;
