import { Layer } from "react-map-gl";
import {
  matchInitialPointLayer,
  unmatchInitialPointLayer,
} from "./layers-config";
import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { usePointSelection } from "../../stores/usePointSelection";
import { STATUSES } from "../../config";
import { useRegionFilterExpression } from "./useRegionFilterExpression";
import { LAYER_IDS } from "./constants";
import { RANGE_FILTERS_KEYS, usePendingPointsFilters } from "../../stores/usePendingPointsFilters";
import { fieldHasChanged, predictionHasChanged } from "../../utils.js";
import { useSourceLayerName } from "../../api.js";

const rawStatusExpression = ["==", ["get", "status"], STATUSES.pending];

const useFilterExpression = () => {
  const { filters, ranges } = usePendingPointsFilters();
  const { prediction, categories, region } = filters;
  const { selection } = usePointSelection();
  const includedArr = [...selection.included];
  const excludedArr = [...selection.excluded];

  const regionExpression = useRegionFilterExpression(region);

  const includedExpression = ["in", ["get", "id"], ["literal", includedArr]];
  const excludedExpression = ["in", ["get", "id"], ["literal", excludedArr]];

  const rawPredictionExpression = [
    [">=", ["get", "prediction_current"], prediction[0]],
    ["<=", ["get", "prediction_current"], prediction[1]],
  ];

  const staticKeyFiltersExpressions = RANGE_FILTERS_KEYS.map((key) => {
    if (/d[0-9]/.test(key) && filters[`${key}__lt`] === 4000) return [
      [">=", ["get", key], filters[`${key}__gt`]]
    ];
    return [
      [">=", ["get", key], filters[`${key}__gt`]],
      ["<=", ["get", key], filters[`${key}__lt`]],
    ];
  });

  const staticKeyExpressions = staticKeyFiltersExpressions.filter((expression) => {
    const filterKey = expression[0][1][1];
    return fieldHasChanged(filters, ranges, filterKey).result;
  }).flat();

  const categoryExpression =
    categories.length > 0
      ? ["in", ["get", "category"], ["literal", categories]]
      : true;

  const statusExpression = rawStatusExpression;
  const predictionExpression = predictionHasChanged(filters, ranges) ? rawPredictionExpression : [true];

  const matchFilterExpression = [
    "all",
    statusExpression,
    ["!", excludedExpression],
    [
      "any",
      regionExpression
        ? ["all", ...predictionExpression, ...staticKeyExpressions, categoryExpression, regionExpression]
        : ["all", ...predictionExpression, ...staticKeyExpressions, categoryExpression],
      includedExpression,
    ],
  ];

  const unmatchFilterExpression = [
    "all",
    statusExpression,
    ["!", includedExpression],
    [
      "any",
      [
        "!",
        regionExpression
          ? [
              "all",
              ...predictionExpression,
              categoryExpression,
              regionExpression,
              ...staticKeyExpressions,
              categoryExpression,
            ]
          : ["all", ...predictionExpression, categoryExpression, ...staticKeyExpressions],
      ],
      excludedExpression,
    ],
  ];

  return { match: matchFilterExpression, unmatch: unmatchFilterExpression };
};

export const PendingPoints = () => {
  const { isVisible } = useLayersVisibility();
  const layerName = useSourceLayerName();
  const { match: matchFilterExpression, unmatch: unmatchFilterExpression } =
    useFilterExpression();

  return (
    <>
      <Layer
        {...matchInitialPointLayer}
        id={LAYER_IDS["initial-unmatch"]}
        source={"points"}
        source-layer={useSourceLayerName()}
        layout={{
          ...matchInitialPointLayer.layout,
          visibility: isVisible[LAYER_IDS.initial] ? "visible" : "none",
        }}
        filter={unmatchFilterExpression}
        paint={unmatchInitialPointLayer.paint}
      />
      <Layer
        {...matchInitialPointLayer}
        id={LAYER_IDS["initial-match"]}
        source={"points"}
        source-layer={layerName}
        layout={{
          ...matchInitialPointLayer.layout,
          visibility: isVisible[LAYER_IDS.initial] ? "visible" : "none",
        }}
        filter={matchFilterExpression}
        paint={matchInitialPointLayer.paint}
      />
    </>
  );
};
