/**
 * Copyright (c) 2023-present Plane Software, Inc. and contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 * See the LICENSE file for details.
 */

import { createContext, useContext, useEffect, useMemo } from "react";
import type { ReactNode } from "react";
import { isEqual } from "lodash-es";
import { observer } from "mobx-react";
import { FilterInstance, workItemFiltersAdapter } from "@plane/shared-state";
import type { IFilterInstance } from "@plane/shared-state";
import type { TWorkItemFilterExpression, TWorkItemFilterProperty } from "@plane/types";
import { useProjectExternalContoursBoard } from "@/hooks/store/use-project-external-contours-board";
import { useExternalContoursFiltersConfig } from "./use-external-contours-filters-config";
import {
  buildExternalContourBoardFilters,
  buildExternalContourRichFilterExpression,
} from "./utils";

const ExternalContoursFilterContext = createContext<
  IFilterInstance<TWorkItemFilterProperty, TWorkItemFilterExpression> | undefined
>(undefined);

type Props = {
  children: ReactNode;
  projectId: string;
  workspaceSlug: string;
};

export const ProjectExternalContoursFiltersProvider = observer(function ProjectExternalContoursFiltersProvider(props: Props) {
  const { children, projectId, workspaceSlug } = props;
  const { filters, items, replaceFilters } = useProjectExternalContoursBoard();

  const requests = useMemo(() => Object.values(items), [items]);
  const { areAllConfigsInitialized, configs } = useExternalContoursFiltersConfig({
    projectId,
    requests,
    workspaceSlug,
  });

  const filter = useMemo(
    () =>
      new FilterInstance<TWorkItemFilterProperty, TWorkItemFilterExpression>({
        adapter: workItemFiltersAdapter,
        initialExpression: buildExternalContourRichFilterExpression(filters),
        onExpressionChange: (expression) => {
          void replaceFilters(workspaceSlug, projectId, buildExternalContourBoardFilters(expression));
        },
      }),
    [projectId, workspaceSlug]
  );

  useEffect(() => {
    filter.onExpressionChange = (expression) => {
      void replaceFilters(workspaceSlug, projectId, buildExternalContourBoardFilters(expression));
    };
  }, [filter, projectId, replaceFilters, workspaceSlug]);

  useEffect(() => {
    filter.configManager.setAreConfigsReady(areAllConfigsInitialized);
    filter.configManager.registerAll(configs);
  }, [areAllConfigsInitialized, configs, filter.configManager]);

  useEffect(() => {
    const nextExpression = buildExternalContourRichFilterExpression(filters);
    const currentExpression = workItemFiltersAdapter.toExternal(filter.expression);

    if (isEqual(currentExpression, nextExpression)) return;

    const onExpressionChange = filter.onExpressionChange;
    filter.onExpressionChange = undefined;
    filter.resetExpression(nextExpression);
    filter.onExpressionChange = onExpressionChange;
  }, [filter, filters]);

  return <ExternalContoursFilterContext.Provider value={filter}>{children}</ExternalContoursFilterContext.Provider>;
});

export const useExternalContoursFilter = () => useContext(ExternalContoursFilterContext);
