/* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useMemo } from "react";
import FilterPopupView from "./FilterPopupView";
import { Operator, OperatorCreiteria } from "../../enum";
import {
  FilterExpression,
  FilterExpressionViewModel,
  FilterTarget,
} from "../../data/advancedSearch";
import {
  getAdvancedSearchIntitialFilterRow,
  isFilterValueEmpty,
  normalizeLogicOperators,
} from "./helper/AdvancedSearchFunctions";
import _ from "lodash";
import { defaultCriteria } from "./constant";

interface FilterPopupProps {
  uiElementGroupData: Record<string, any>;
  filterableFields: FilterTarget[];
  config: { uiElementGroupId: string };
  cache?: Record<string, any[]>;
  loadSupportiveData: (propertyToFilter: FilterTarget) =>Promise<void>;
  handlePopupShow: () => void;
  onModelUpdate: (
    callBack: ((args: any) => void) | null,
    fieldName: string,
    value: any,
  ) => void;
  loadTemplateSupportiveData?: (
    callBack: (args: any) => void,
    supportiveKeys: any,
  ) => Promise<any>;
}

const FilterPopup = (props: FilterPopupProps) => {
  // If appliedQuery has data but filterRows doesn't, populate filterRows from appliedQuery.filters
  useEffect(() => {
    const advancedSearch = props.uiElementGroupData?.advancedSearch;
    const hasAppliedQuery = advancedSearch?.appliedQuery?.filters?.length > 0;
    const hasValidFilterRows =
      advancedSearch?.filterRows?.length > 0 &&
      advancedSearch?.filterRows[0]?.selectedFilter?.propertyToFilter
        ?.apiPropertyName;

    if (hasAppliedQuery && !hasValidFilterRows) {
      const filterRows: FilterExpressionViewModel[] = [];
      let criteria = advancedSearch.appliedQuery.criteria;

      advancedSearch.appliedQuery.filters.forEach(
        (filter: FilterExpression, index: number) => {
          const filterRow: FilterExpressionViewModel = {
            id: filter.id,
            idLabel: `(${(index + 1).toString()})`,
            selectedFilter: _.cloneDeep(filter),
            allPropertieseToFilter: props.filterableFields,
            alloperators: [],
            allValues: undefined,
          };
          criteria = criteria.replace(filter.id, filterRow.idLabel);
          filterRows.push(filterRow);
        },
      );

      const updatedAdvancedSearch = {
        ...advancedSearch,
        filterRows: _.cloneDeep(filterRows),
        criteria,
      };

      const updatedUiElementGroupData = {
        ...props.uiElementGroupData,
        advancedSearch: updatedAdvancedSearch,
      };

      props.onModelUpdate(
        null,
        props.config.uiElementGroupId,
        updatedUiElementGroupData,
      );
    }
  }, []);

  const onAdvancedSearchFilterTargetChange = (
    value: FilterTarget,
    id: string,
  ) => {
    const filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );

    const filterRow = filterRows.find(
      (filterRow: FilterExpressionViewModel) => filterRow.id === id,
    );

    if (filterRow) {
      filterRow.selectedFilter.propertyToFilter = value;
      filterRow.selectedFilter.value = undefined;
      filterRow.selectedFilter.operator = {
        label: "Select Operator...",
        value: null,
      };
    }
    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: filterRows,
      },
    };
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchOperatorChange = (
    value: {
      label: string;
      value: Operator | null;
    },
    id: string,
  ) => {
    const filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );
    const filterRow = filterRows.find(
      (filterRow: FilterExpressionViewModel) => filterRow.id === id,
    );
    if (filterRow) {
      filterRow.selectedFilter.operator = value;
      filterRow.selectedFilter.value = undefined;
    }
    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: filterRows,
      },
    };
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchFilterValueChange = (value: any, id: string) => {
    const filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );
    const filterRow = filterRows.find(
      (filterRow: FilterExpressionViewModel) => filterRow.id === id,
    );
    if (filterRow) {
      filterRow.selectedFilter.value = value;
    }
    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: filterRows,
      },
    };
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchCriteriaToggle = (id: string) => {
    const filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );
    const filterRow = filterRows.find(
      (filterRow: FilterExpressionViewModel) => filterRow.id === id,
    );
    if (filterRow) {
      filterRow.selectedFilter.selectedCriteria =
        filterRow.selectedFilter.selectedCriteria === OperatorCreiteria.AND
          ? OperatorCreiteria.OR
          : OperatorCreiteria.AND;
    }
    let criteria = "";
    filterRows.map((filterRow: any, index: number) => {
      criteria += `${filterRow.idLabel}`;
      if (filterRows?.length - 1 !== index) {
        criteria += ` ${filterRow?.selectedFilter?.selectedCriteria} `;
      }
    });
    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: filterRows,
        criteria,
      },
    };
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchFilterAdd = (id: string) => {
    const idPosition =
      props.uiElementGroupData.advancedSearch.filterRows.findIndex(
        (filterRow: FilterExpressionViewModel) => filterRow.id === id,
      );

    const initialFilterRow = _.cloneDeep(getAdvancedSearchIntitialFilterRow());
    initialFilterRow.allPropertieseToFilter = props.filterableFields;

    let updatedFilterRows = [
      ...props.uiElementGroupData.advancedSearch.filterRows.slice(
        0,
        idPosition + 1,
      ),
      initialFilterRow,
      ...props.uiElementGroupData.advancedSearch.filterRows.slice(
        idPosition + 1,
      ),
    ];
    let criteria = "";
    updatedFilterRows = _.cloneDeep(updatedFilterRows).map((row, index) => {
      row.idLabel = `(${index + 1})`;
      criteria += `${row.idLabel}`;
      if (updatedFilterRows?.length - 1 !== index) {
        criteria += ` ${row?.selectedFilter?.selectedCriteria} `;
      }

      return row;
    });

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: updatedFilterRows,
        criteria: criteria?.trim(),
      },
    };

    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchFilterDelete = (id: string) => {
    let filterRows = props.uiElementGroupData.advancedSearch.filterRows.filter(
      (filterRow: FilterExpressionViewModel) => filterRow.id !== id,
    );

    let criteriaExpression = "";

    filterRows = _.cloneDeep(filterRows)?.map(
      (filterRow: FilterExpressionViewModel, index: number) => {
        filterRow.idLabel = `(${index + 1})`;
        criteriaExpression += filterRow.idLabel;
        if (filterRows?.length - 1 !== index) {
          criteriaExpression += ` ${filterRow.selectedFilter.selectedCriteria} `;
        }
        return filterRow;
      },
    );

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: filterRows,
        criteria: criteriaExpression,
      },
      pagination: { ...props.uiElementGroupData.pagination, skip: 0 },
    };

    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchClear = () => {
    const initialFilterRow = _.cloneDeep(getAdvancedSearchIntitialFilterRow());
    initialFilterRow.allPropertieseToFilter = props.filterableFields;

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: {
        ...props.uiElementGroupData.advancedSearch,
        filterRows: [initialFilterRow],
        criteria: defaultCriteria,
        appliedQuery: {
          criteria: "",
          filters: [],
        },
      },
    };
    props.handlePopupShow();
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onCriteriaApplied = () => {
    let criteriaExpression = document.getElementById(
      "tmpl-criteria-input-" + (props.config.uiElementGroupId ?? ""),
    )?.innerText;

    criteriaExpression = normalizeLogicOperators(criteriaExpression ?? "");
    const operators = [...(criteriaExpression?.matchAll(/AND|OR/gi) ?? [])].map(
      (match) => match[0],
    );

    let filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );

    filterRows = filterRows.map((filterRow: any, index: number) => {
      if (filterRows?.length - 1 !== index) {
        filterRow.selectedFilter.selectedCriteria = operators[index] ?? "AND";
      }

      return filterRow;
    });

    const updatedAdvancedSearch = {
      ...props.uiElementGroupData.advancedSearch,
      filterRows: filterRows,
      criteria: criteriaExpression ?? "",
    };

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: updatedAdvancedSearch,
    };

    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onCopyToClipboard = async () => {
    const criteria = document.getElementById(
      "tmpl-criteria-input-" + (props.config.uiElementGroupId ?? ""),
    )?.innerText;
    try {
      await navigator.clipboard.writeText(criteria || "");
    } catch (err) {
      console.error("Unable to copy to clipboard", err);
    }
  };

  const onAdvancedSearchCancel = () => {
    const clonedFilterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );
    const filterRows: FilterExpressionViewModel[] = [];
    let criteria =
      props.uiElementGroupData.advancedSearch.appliedQuery.criteria;

    props.uiElementGroupData.advancedSearch.appliedQuery?.filters?.map(
      (filter: any, index: number) => {
        const clonedFilterRow = clonedFilterRows?.find(
          (row: any) => row.id === filter.id,
        );

        const filterRow: FilterExpressionViewModel = {
          id: filter.id,
          idLabel: `(${(index + 1).toString()})`,
          selectedFilter: _.cloneDeep(filter),
          allPropertieseToFilter: props.filterableFields,
          alloperators: clonedFilterRow?.alloperators ?? [],
          allValues: clonedFilterRow ? clonedFilterRow?.allValues : undefined,
        };
        criteria = criteria.replace(filter.id, filterRow.idLabel);
        filterRows.push(filterRow);
      },
    );

    if (!filterRows.length) {
      const initialFilterRow = _.cloneDeep(
        getAdvancedSearchIntitialFilterRow(),
      );
      initialFilterRow.allPropertieseToFilter = props.filterableFields;
      filterRows.push(initialFilterRow);
      criteria = defaultCriteria;
    }

    const updatedAdvancedSearch = {
      ...props.uiElementGroupData.advancedSearch,
      filterRows: _.cloneDeep(filterRows),
      criteria,
    };

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: updatedAdvancedSearch,
    };

    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const onAdvancedSearchApply = () => {
    const filterRows = _.cloneDeep(
      props.uiElementGroupData.advancedSearch.filterRows,
    );

    const selectedFilters: FilterExpression[] = [];
    let criteria = props.uiElementGroupData?.advancedSearch?.criteria ?? "";

    filterRows?.map((filterRow: FilterExpressionViewModel) => {
      selectedFilters.push(filterRow.selectedFilter);
      criteria = criteria.replace(filterRow.idLabel, filterRow.id);
    });

    const appliedQuery = {
      criteria,
      filters: selectedFilters,
    };

    const updatedAdvancedSearch = {
      ...props.uiElementGroupData.advancedSearch,
      appliedQuery: _.cloneDeep(appliedQuery),
    };

    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      advancedSearch: updatedAdvancedSearch,
      pagination: { ...props.uiElementGroupData.pagination, skip: 0 },
    };
    props.handlePopupShow();
    props.onModelUpdate(
      null,
      props.config.uiElementGroupId,
      updatedUiElementGroupData,
    );
  };

  const hasValidFilter = useMemo(() => {
    const filterRows: FilterExpressionViewModel[] =
      props.uiElementGroupData?.advancedSearch?.filterRows ?? [];
    return filterRows.some(
      (row) =>
        row.selectedFilter?.propertyToFilter?.apiPropertyName &&
        row.selectedFilter?.operator?.value != null &&
        !isFilterValueEmpty(row.selectedFilter?.value),
    );
  }, [props.uiElementGroupData?.advancedSearch?.filterRows]);

  const hasAppliedFilter = useMemo(() => {
    const appliedFilters =
      props.uiElementGroupData?.advancedSearch?.appliedQuery?.filters ?? [];
    return appliedFilters.length > 0;
  }, [props.uiElementGroupData?.advancedSearch?.appliedQuery?.filters]);

  const isDirty = useMemo(() => {
    const filterRows: FilterExpressionViewModel[] =
      props.uiElementGroupData?.advancedSearch?.filterRows ?? [];
    const appliedQuery =
      props.uiElementGroupData?.advancedSearch?.appliedQuery;
    const appliedFilters = appliedQuery?.filters ?? [];
    const currentCriteria =
      props.uiElementGroupData?.advancedSearch?.criteria ?? "";

    // Build comparable current filters from filterRows
    const currentFilters = filterRows.map((row) => ({
      apiPropertyName: row.selectedFilter?.propertyToFilter?.apiPropertyName,
      operator: row.selectedFilter?.operator?.value,
      value: row.selectedFilter?.value,
      selectedCriteria: row.selectedFilter?.selectedCriteria,
    }));

    // Build comparable applied filters
    const appliedComparable = appliedFilters.map(
      (filter: FilterExpression) => ({
        apiPropertyName: filter.propertyToFilter?.apiPropertyName,
        operator: filter.operator?.value,
        value: filter.value,
        selectedCriteria: filter.selectedCriteria,
      }),
    );

    // Also compare criteria expression
    const appliedCriteria = appliedQuery?.criteria ?? "";
    // Reconstruct current criteria with IDs for comparison
    let currentCriteriaWithIds = currentCriteria;
    filterRows.forEach((row) => {
      currentCriteriaWithIds = currentCriteriaWithIds.replace(
        row.idLabel,
        row.id,
      );
    });

    return (
      JSON.stringify(currentFilters) !== JSON.stringify(appliedComparable) ||
      currentCriteriaWithIds !== appliedCriteria
    );
  }, [
    props.uiElementGroupData?.advancedSearch?.filterRows,
    props.uiElementGroupData?.advancedSearch?.appliedQuery,
    props.uiElementGroupData?.advancedSearch?.criteria,
  ]);

  return (
    <FilterPopupView
      uiElementGroupId={props.config.uiElementGroupId}
      filterRows={props.uiElementGroupData?.advancedSearch?.filterRows ?? []}
      criteria={props.uiElementGroupData?.advancedSearch?.criteria ?? ""}
      cache={props.cache}
      onFilterTargetChange={onAdvancedSearchFilterTargetChange}
      onOperatorChange={onAdvancedSearchOperatorChange}
      onFilterValueChange={onAdvancedSearchFilterValueChange}
      onCriteriaToggle={onAdvancedSearchCriteriaToggle}
      onAddFilter={onAdvancedSearchFilterAdd}
      onDeleteFilter={onAdvancedSearchFilterDelete}
      onClear={onAdvancedSearchClear}
      onCriteriaApplied={onCriteriaApplied}
      onCopyToClipboard={onCopyToClipboard}
      onCancel={onAdvancedSearchCancel}
      onApply={onAdvancedSearchApply}
      loadSupportiveData={props.loadSupportiveData}
      isApplyDisabled={!hasValidFilter || !isDirty}
      isClearDisabled={!hasAppliedFilter && !hasValidFilter}
    />
  );
};

export default FilterPopup;
