import React, { useMemo, useRef } from "react";
import { Modal } from "../Modal";
import { ButtonGroup } from "../ButtonGroup";
import { Button } from "../Button";
import { useState, useEffect } from "react";
import { AddOutlined } from "@mui/icons-material";
import { Toast } from "../Toast";
import AdvanceSearchModalItem from "./AdvanceSearchModalItem";
import { useForm, useFieldArray } from "react-hook-form";
import {
  convertToOptions,
  getAllowedColumns,
  hasDuplicateColumns,
  NON_TEXT_FILTER_OPTIONS,
  TEXT_FILTER_OPTIONS,
} from "../../utils/helper";
import moment from "moment";
import { cloneDeep } from "lodash";
import { on } from "events";

export default function AdvanceSearchModal({
  isAdvanceSearch,
  toggleAdvanceSearch,
  colDefs,
  actualRef,
  currentColumnId,
  savedAdvanceSearchConfig,
  setInitialFilters,
  initialFilters = [{ column: null, operation: null, value: "" }],
  selectedThirdOptionDropdownValue,
  setSelectedThirdOptionDropdownValue,
  draftFilter,
  setDraftFilter,
  ...args
}) {
  const [activeOption, setActiveOption] = useState("advanceSearch");
  const [initialDataSet, setInitialDataSet] = useState(false);
  const [isFormValid, setIsFormValid] = useState(true);
  const [openToast, setOpenToast] = useState(false);
  const [isClearAll, setIsClearAll] = useState(false);
  const [flag, setFlag] = useState(false);
  const [_, forceRender] = useState(false);

  const [
    toShowDuplicateColumnInAdvanceSearch,
    setToShowDuplicateColumnInAdvanceSearch,
  ] = useState(false);

  const formMethods =
    activeOption == "advanceSearch"
      ? useForm({
          defaultValues: {
            filters: initialFilters,
          },
          rules: {
            required: true,
          },
        })
      : useForm({
          defaultValues: {
            filters: [{ column: null, operation: null, value: null }],
          },
          rules: {
            required: true,
          },
        });

  const { control, handleSubmit, reset, getValues, watch, setValue } =
    formMethods;
  const { fields, append, remove } = useFieldArray({
    control,
    name: "filters",
    keyName: "fieldId",
  });

  const [pendingDeletions, setPendingDeletions] = useState([]);
  const [softCleared, setSoftCleared] = useState(false);
  // code for removing repeating field name

  const allowedCols = useMemo(() => {
    return getAllowedColumns(colDefs);
  }, [colDefs]);

  // Using `flag` in dependency array because `fields` is an array of objects,
  // and changes to object properties inside it don't trigger `useMemo`.
  // Toggling `flag` ensures the memoized value recomputes on updates.

  const filteredColumnsInitialOptions = useMemo(() => {
    const selectedValues = fields
      .filter((field) => !pendingDeletions.includes(field.fieldId))
      .map((f) => f.column?.value)
      .filter(Boolean);

    return convertToOptions(colDefs || []).filter(
      (opt) => !selectedValues.includes(opt.value)
    );
  }, [colDefs, fields, flag, pendingDeletions]);

  // Set initial form values from filter model

  useEffect(() => {
    if (
      !initialDataSet &&
      actualRef?.current?.api &&
      actualRef?.current?.api?.getFilterModel()
    ) {
      // Helper function to check if a filter is truly empty
      const isEmptyFilter = (filter) => {
        return (
          !filter?.column?.value ||
          filter?.column?.value === null ||
          filter?.column?.value === "" ||
          (!filter?.operation?.value && !filter?.value)
        );
      };

      // Check if initialFilters was intentionally cleared (all filters are empty or empty array)
      const validInitialFilters =
        initialFilters?.filter((f) => !isEmptyFilter(f)) || [];
      const isIntentionallyCleared =
        initialFilters?.length === 0 || // Empty array means cleared
        (initialFilters?.length > 0 && validInitialFilters.length === 0); // Array with only empty filters

      // If filters were intentionally cleared, don't restore from filter model
      if (isIntentionallyCleared) {
        reset({ filters: [{ column: null, operation: null, value: "" }] });
        setInitialDataSet(true);
        return;
      }

      const filterModel = actualRef.current.api?.getFilterModel();
      if (Object.keys(filterModel)?.length > 0) {
        const formattedFilters = Object.entries(filterModel)?.map(
          ([field, filterData]) => {
            const columnOption = filteredColumnsInitialOptions?.find(
              (opt) => opt?.value === field
            );

            const columnsOptionsInfo = colDefs?.find(
              (col) => col?.field === field
            );
            const isThirdOptionDropdown =
              columnsOptionsInfo?.thirdOptionAsDropdown;

            const getThirdOptionDropdownValue = (filterData) => {
              if (isThirdOptionDropdown) {
                return columnsOptionsInfo?.thirdOptionDropdownOptions?.find(
                  (item) => item?.value === filterData
                );
              }
              return filterData;
            };

            const filterValue = getThirdOptionDropdownValue(filterData?.filter);

            const operationOption =
              filterData.filterType === "number"
                ? NON_TEXT_FILTER_OPTIONS?.find(
                    (opt) => opt?.value === filterData?.type
                  )
                : TEXT_FILTER_OPTIONS?.find(
                    (opt) => opt?.value === filterData?.type
                  );

            return {
              column: columnOption,
              operation: operationOption,
              value:
                filterData?.filterType === "date"
                  ? moment(filterValue)
                  : filterValue,
              id: "", // no uuid for now
            };
          }
        );

        // Filter out empty filters from initialFilters
        const validInitialFilters =
          initialFilters?.filter((f) => !isEmptyFilter(f)) || [];

        const updatedInitialFilters = [
          // Include valid initial filters, updated with formattedFilters if they match
          ...validInitialFilters?.map((filter) => {
            const match = formattedFilters?.find(
              (f) => f?.column?.value === filter?.column?.value
            );
            return match || filter;
          }),

          // Add new filters from formattedFilters that don't exist in initialFilters
          ...formattedFilters?.filter(
            (f) =>
              f?.column?.value && // column.value must be there
              f?.operation?.value && // operation must be there
              !validInitialFilters?.find(
                (filter) => filter?.column?.value === f?.column?.value
              )
          ),
        ];

        // If no valid filters exist, add one empty filter as default
        const finalFilters =
          updatedInitialFilters.length > 0
            ? updatedInitialFilters
            : [{ column: null, operation: null, value: "" }];

        reset({ filters: finalFilters });
        setInitialDataSet(true);
      } else {
        // Handle case when filterModel is empty - still need to initialize
        const isEmptyFilter = (filter) => {
          return (
            !filter?.column?.value ||
            filter?.column?.value === null ||
            filter?.column?.value === "" ||
            (!filter?.operation?.value && !filter?.value)
          );
        };

        const validInitialFilters =
          initialFilters?.filter((f) => !isEmptyFilter(f)) || [];
        const finalFilters =
          validInitialFilters.length > 0
            ? validInitialFilters
            : [{ column: null, operation: null, value: "" }];

        reset({ filters: finalFilters });
        setInitialDataSet(true);
      }
    } else if (initialFilters?.length > 0 && !initialDataSet) {
      // Apply same empty filter logic here too
      const isEmptyFilter = (filter) => {
        return (
          !filter?.column?.value ||
          filter?.column?.value === null ||
          filter?.column?.value === "" ||
          (!filter?.operation?.value && !filter?.value)
        );
      };

      const validInitialFilters =
        initialFilters?.filter((f) => !isEmptyFilter(f)) || [];
      const finalFilters =
        validInitialFilters.length > 0
          ? validInitialFilters
          : [{ column: null, operation: null, value: "" }];

      reset({ filters: finalFilters });
      setInitialDataSet(true);
    } else if (!initialDataSet) {
      // Final fallback - ensure we always have at least one empty filter
      reset({ filters: [{ column: null, operation: null, value: "" }] });
      setInitialDataSet(true);
    }
  }, [
    actualRef,
    filteredColumnsInitialOptions,
    initialDataSet,
    initialFilters,
  ]);

  // helper: remove visually only
  const softRemove = (index, fieldId) => {
    const filter = getValues()?.filters[index];
    // If the row has no column selected, remove it directly.
    if (!filter?.column?.value) {
      remove(index);
    } else {
      // Otherwise, add it to pending deletions for a soft delete.
      setPendingDeletions((prev) => [...prev, fieldId]);
    }
  };

  useEffect(() => {
    if (isAdvanceSearch) {
      // Helper function to check if a filter is truly empty
      const isEmptyFilter = (filter) => {
        return (
          !filter?.column?.value ||
          filter?.column?.value === null ||
          filter?.column?.value === "" ||
          (!filter?.operation?.value && !filter?.value)
        );
      };

      // Check if initialFilters was intentionally cleared (all filters are empty or empty array)
      const validInitialFilters =
        initialFilters?.filter((f) => !isEmptyFilter(f)) || [];
      const isIntentionallyCleared =
        initialFilters?.length === 0 || // Empty array means cleared
        (initialFilters?.length > 0 && validInitialFilters.length === 0); // Array with only empty filters

      // If filters were intentionally cleared, don't restore from filter model
      if (isIntentionallyCleared) {
        reset({ filters: [{ column: null, operation: null, value: "" }] });
        setIsClearAll(false);
        return;
      }

      const filterModel = args?.api?.getFilterModel?.() || {};
      const newFilters = [];
      Object.keys(filterModel).forEach((colId) => {
        const columnDef = colDefs.find(
          (col) => col?.colId === colId || col?.field === colId
        );
        if (!columnDef) return;

        let value = "";
        let operation = "";

        if (columnDef.filter === "agDateColumnFilter") {
          value = filterModel[colId]?.dateFrom || "";
          operation = "equals";
        } else if (columnDef.filter === "agNumberColumnFilter") {
          value = filterModel[colId]?.filter?.toString?.() || "";
          operation = filterModel[colId]?.type || "equals";
        } else {
          value = filterModel[colId]?.filter?.toString?.() || "";
          operation = "contains";
        }

        if (value) {
          newFilters.push({
            column: {
              label: columnDef.headerName,
              value: colId,
            },
            operation: {
              label: operation.charAt(0).toUpperCase() + operation.slice(1),
              value: operation,
            },
            value: value,
          });
        }
      });

      // If user typed filter in grid search box
      if (newFilters.length > 0) {
        reset({ filters: newFilters });
      } else {
        // ✅ Get filters from actualRef (agGrid)
        const actualFilters = actualRef?.current?.api?.getFilterModel?.() || {};
        const fieldOrder = Object.keys(actualFilters); // 👈 This maintains order

        const tempExtraFilters = fieldOrder?.map((colId) => {
          const filter = actualFilters[colId];
          return {
            column: {
              label: colId?.charAt(0)?.toUpperCase() + colId?.slice(1),
              value: colId,
              type: filter?.filterType || "text",
            },
            operation: {
              label:
                filter?.type?.charAt(0)?.toUpperCase() +
                  filter?.type?.slice(1) || "Contains",
              value: filter?.type || "contains",
            },
            value: filter?.dateFrom || filter?.filter || "",
            id: "",
          };
        });

        // Remove duplicates if needed
        const merged = [
          ...tempExtraFilters,
          ...validInitialFilters?.filter(
            (f) => !fieldOrder?.includes(f?.column?.value)
          ),
        ];

        reset({
          filters:
            merged.length > 0
              ? merged
              : [{ column: null, operation: null, value: "" }],
        });
      }

      setIsClearAll(false);
    }
  }, [isAdvanceSearch, initialFilters, colDefs, args?.api]);

  useEffect(() => {
    if (!isAdvanceSearch) return;

    // Helper function to check if a filter is truly empty
    const isEmptyFilter = (filter) => {
      return (
        !filter?.column?.value ||
        filter?.column?.value === null ||
        filter?.column?.value === "" ||
        (!filter?.operation?.value && !filter?.value)
      );
    };

    // Check if initialFilters was intentionally cleared (all filters are empty or empty array)
    const validInitialFilters =
      initialFilters?.filter((f) => !isEmptyFilter(f)) || [];
    const isIntentionallyCleared =
      initialFilters?.length === 0 || // Empty array means cleared
      (initialFilters?.length > 0 && validInitialFilters.length === 0); // Array with only empty filters

    // If filters were intentionally cleared, don't restore from draftFilter or initialFilters
    if (isIntentionallyCleared) {
      reset({ filters: [{ column: null, operation: null, value: "" }] });
      setIsClearAll(false);
      return;
    }

    if (draftFilter?.length > 0) {
      // Merge logic: combine draftFilter with any new columns from initialFilters
      const draftColumnValues = draftFilter
        .map((f) => f?.column?.value)
        .filter(Boolean);
      const newColumnsFromInitial =
        validInitialFilters?.filter(
          (f) =>
            f?.column?.value && !draftColumnValues.includes(f?.column?.value)
        ) || [];

      const mergedFilters = [...draftFilter, ...newColumnsFromInitial];

      reset({ filters: mergedFilters });
    } else {
      reset({
        filters:
          validInitialFilters.length > 0
            ? validInitialFilters
            : [{ column: null, operation: null, value: "" }],
      });
    }

    setIsClearAll(false);
  }, [isAdvanceSearch, initialFilters, draftFilter]);

  const onSubmit = (data) => {};

  const handleClearAll = () => {
    const currentFilters = getValues()?.filters || [];

    // Save current filters in case user closes modal without applying
    const clonedFilters = cloneDeep(
      currentFilters.filter((f) => f?.column?.value)
    );
    setDraftFilter(clonedFilters);

    reset({
      filters: [
        {
          column: null,
          operation: null,
          value: "",
        },
      ],
    });
    setSoftCleared(true);
    setIsClearAll(true);

    // Immediately clear AG Grid filter model and advanced filter model
    actualRef?.current?.api?.setFilterModel(null);

    // Clear advanced filter model as well
    const model = actualRef?.current?.api?.getModel();
    if (model?.advancedFilterModel) {
      model.advancedFilterModel = {};
    }

    // Trigger filter change to update UI immediately
    Promise.resolve().then(() => {
      actualRef?.current?.api?.onFilterChanged();
    });

    // Update initialFilters immediately
    setInitialFilters([{ column: null, operation: null, value: "" }]);

    // Reset initialDataSet to force reinitialization on next open
    setInitialDataSet(false);

    args?.onClearAllClick?.();
  };
  const handleClearAllValues = () => {
    const allFilters = getValues()?.filters || [];
    const updatedFilters = allFilters
      ?.filter((filter, index) => {
        const fieldId = fields[index]?.fieldId;
        // Exclude fields that are pending deletion AND have empty columns
        return !pendingDeletions?.includes(fieldId) && filter?.column !== "";
      })
      .map((filter) => ({
        ...filter,
        value: undefined,
      }));
    reset({
      filters:
        updatedFilters?.length > 0
          ? updatedFilters
          : [
              {
                column: { label: "", value: "", type: "text" },
                operation: null,
                value: undefined,
              },
            ],
    });
  };

  const watchedFilters = watch("filters");
  const watchedColumns = watchedFilters?.map((filter) => filter?.column?.value);

  useEffect(() => {
    // Filter out null/empty values before checking for duplicates
    const nonEmptyColumns = watchedColumns?.filter(
      (col) => col !== null && col !== undefined && col !== ""
    );
    const hasDuplicates = hasDuplicateColumns(nonEmptyColumns);
    // Only validate if there are actual column selections, ignore empty fields
    setIsFormValid(!hasDuplicates);
  }, [watchedColumns]);
  useEffect(() => {
    if (!isFormValid) {
      setOpenToast(true);
    }
  }, [isFormValid]);

  const handleApplyFilters = () => {
    const allFilters = getValues()?.filters || [];
    setDraftFilter([]); // Always clear draftFilter when applying
    const updatedFilters = allFilters?.filter((field, index) => {
      const fieldId = fields[index]?.fieldId;
      return (
        !pendingDeletions?.includes(fieldId) &&
        field?.column?.value &&
        field?.operation?.value
      );
    });

    if (softCleared) {
      // Filters were already cleared in handleClearAll, just need to apply
      // Pass empty array to onSearchApplyClick
      args.onSearchApplyClick([]);
      setSoftCleared(false);
      setIsClearAll(false);
      setPendingDeletions([]);
      return; // Exit early - don't process filters
    } else {
      setInitialFilters(updatedFilters);
    }

    args.onSearchApplyClick(updatedFilters);
    const finalModel = updatedFilters?.reduce((acc, curr) => {
      if (curr?.column?.value && curr?.operation?.value) {
        let filterValue = curr?.value?.value || curr?.value;
        let filterType = "text";

        if (moment?.isMoment(filterValue)) {
          filterType = "date";
          filterValue = filterValue?.format("YYYY-MM-DD");
        }

        acc[curr?.column?.value] = {
          filter: filterValue,
          filterType,
          type: curr?.operation?.value,
          ...(filterType === "date" && { dateFrom: filterValue }),
        };
      }
      return acc;
    }, {});

    setSoftCleared(false);

    actualRef?.current?.api?.setFilterModel(finalModel);

    Promise.resolve().then(() => {
      actualRef?.current?.api?.onFilterChanged();
    });

    actualRef?.current?.api?.setFilterModel(finalModel);

    // Important: to update UI like search text in AgGridHeader
    Promise.resolve().then(() => {
      actualRef?.current?.api?.onFilterChanged();
    });

    setIsClearAll(false);
    setPendingDeletions([]); // clear state
  };

  const handleAdvanceSearchClose = () => {
    const currentFilters = getValues()?.filters || [];

    const cleanedFilters = currentFilters.filter((f) => {
      const hasColumn = f?.column?.value;
      const hasOperation = f?.operation?.value;
      const hasValue =
        typeof f?.value === "string"
          ? f?.value?.trim() !== ""
          : f?.value !== null && f?.value !== undefined;

      return hasColumn && (hasOperation || hasValue);
    });

    setPendingDeletions([]);
    setInitialFilters(cleanedFilters);
  };

  // Filter out the temporarily deleted fields to get only the visible ones on UI
  const visibleFields = fields?.filter(
    (field) => !pendingDeletions?.includes(field.fieldId)
  );

  return (
    <Modal
      className="ia-table-search-modal"
      onClose={() => {
        setPendingDeletions([]);
        // Reset initialDataSet when modal closes so it reinitializes on next open
        setInitialDataSet(false);
        toggleAdvanceSearch();
        if (!softCleared) {
          handleAdvanceSearchClose();
        }
        setSoftCleared(false);
        setIsClearAll(false);
      }}
      onPrimaryButtonClick={handleApplyFilters}
      onSecondaryButtonClick={(e) => {
        e.preventDefault();
        args?.onSearchSaveClick(getValues()?.filters);
      }}
      primaryButtonProps={{
        type: "submit",
        disabled: !isFormValid,
      }}
      secondaryButtonProps={{
        disabled: !isFormValid,
      }}
      primaryButtonLabel="Apply"
      secondaryButtonLabel={args?.onSearchSaveClick ? "Save search" : null}
      size="small"
      title="Search"
      width={850}
      height={400}
      open={isAdvanceSearch}
    >
      <div className="ia-table-search-header">
        <ButtonGroup
          options={[
            {
              label: "Search",
              value: "search",
            },
            {
              label: "Advance Search",
              value: "advanceSearch",
            },
          ]}
          selectedOption={activeOption}
          onChange={(e, val) => {
            e.preventDefault();
            setActiveOption(val);
            actualRef?.current?.api?.destroyFilter(null);

            // New logic to conditionally clear only operation if value is blank
            if (val === "advanceSearch") {
              const updatedFilters = getValues()?.filters?.map((filter) => {
                const shouldResetOp =
                  filter.value === null || filter.value === "" || !filter.value;

                return {
                  ...filter,
                  operation: shouldResetOp ? null : filter.operation,
                };
              });
              reset({ filters: updatedFilters });
            }
          }}
        />

        <Button
          variant="url"
          size="small"
          type="button"
          onClick={(e) => {
            e.preventDefault();
            handleClearAll();
          }}
        >
          Clear all
        </Button>
      </div>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          handleSubmit(onSubmit)(e);
        }}
        className="ia-table-search-content"
      >
        <div className="ia-table-search-content-title">
          Match all of the following rules
        </div>

        <>
          {savedAdvanceSearchConfig?.length > 0
            ? savedAdvanceSearchConfig
            : (() => {
                return fields
                  ?.filter(
                    (field) => !pendingDeletions?.includes(field.fieldId)
                  )
                  ?.map((field, visualIndex) => {
                    // Find the actual index in the full fields array
                    const actualIndex = fields.findIndex(
                      (f) => f.fieldId === field.fieldId
                    );
                    return (
                      <AdvanceSearchModalItem
                        key={field.fieldId}
                        colDefs={colDefs}
                        control={control}
                        index={visualIndex} // Visual index for UI purposes
                        actualIndex={actualIndex} // Actual form index
                        fields={fields}
                        filteredColumnsInitialOptions={
                          filteredColumnsInitialOptions
                        }
                        onDelete={() => {
                          softRemove(actualIndex, field.fieldId);
                        }}
                        totalColumns={fields.length}
                        currentColumnId={currentColumnId}
                        activeOption={activeOption}
                        getValues={getValues}
                        addNewColumn={append}
                        isClearAll={isClearAll}
                        setToShowDuplicateColumnInAdvanceSearch={
                          setToShowDuplicateColumnInAdvanceSearch
                        }
                        selectedThirdOptionDropdownValue={
                          selectedThirdOptionDropdownValue
                        }
                        setSelectedThirdOptionDropdownValue={
                          setSelectedThirdOptionDropdownValue
                        }
                        flag={flag}
                        setFlag={setFlag}
                        isLastVisible={visibleFields.length === 1}
                        pendingDeletions={pendingDeletions}
                        setPendingDeletions={setPendingDeletions}
                        remove={remove}
                        {...args}
                      />
                    );
                  });
              })()}
        </>
        {!isFormValid && (
          <Toast
            isOpen={openToast}
            message="Please select an unselected column "
            onClose={() => setOpenToast(!openToast)}
            position="top-right"
            variant="warning"
          />
        )}
        <div className="ia-table-search-content-footer">
          <Button
            variant="secondary"
            size="large"
            onClick={handleClearAllValues}
            type="button"
            disabled={filteredColumnsInitialOptions?.length === 1}
          >
            Clear values
          </Button>
          <Button
            variant="tertiary"
            size="large"
            type="button"
            onClick={() => {
              append({
                column: "",
                operation: "",
                value: "",
              });
            }}
            disabled={visibleFields.length === allowedCols.length}
            icon={<AddOutlined />}
          >
            Add attribute
          </Button>
        </div>
      </form>
    </Modal>
  );
}
