import { createContext, useEffect, useState } from "react";
import { toast } from "react-toastify";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { flattenArrayOfObjects } from "@/core/utils/flattenArrayOfObjects";
import AskForKeepData from "@/core/components/NotificationDesign/AskForKeepData";
import { LinearProgress } from "@mui/material";

export const DataTableContext = createContext();

const DataTableProvider = ({
  children,
  user_id,
  page_name,
  table_name,
  columns,
  initialSort = [],
}) => {
  const { settingStore } = useTableSetting();
  const [isInitStates, setInitStates] = useState(false);
  const flatColumns = flattenArrayOfObjects(columns, "columns");
  const [initFilter, setInitFilter] = useState({});
  const [filterData, setFilterData] = useState({});
  const [initSort, setInitSort] = useState(initialSort || []);
  const [sortData, setSortData] = useState(initialSort || []);
  const [initHide, setInitHide] = useState({});
  const [hideData, setHideData] = useState({});
  const [isDirty, setIsDirty] = useState(false);
  const [isAnyDirty, setIsAnyDirty] = useState(false);

  useEffect(() => {
    let hasAnyConflict = false;
    const hasConflict =
      JSON.stringify(hideData) !== JSON.stringify(initHide) ||
      JSON.stringify(sortData) !== JSON.stringify(initSort) ||
      JSON.stringify(filterData) !== JSON.stringify(initFilter);

    const CheckFilterValues = Object.values(filterData).every((innerObject) => {
      if (
        innerObject.datatype === "date" &&
        innerObject.filterMode === "between"
      ) {
        return (
          Array.isArray(innerObject.value) &&
          innerObject.value.length === 2 &&
          innerObject.value.every((v) => v === "")
        );
      } else {
        return innerObject.value === "";
      }
    });
    const flattenObject = (obj) => {
      let result = {};
      for (const key in obj) {
        if (typeof obj[key] === "object" && obj[key] !== null) {
          Object.assign(result, flattenObject(obj[key])); // باز کردن اشیای تودرتو
        } else {
          result[key] = obj[key];
        }
      }
      return result;
    };

    // تبدیل آبجکت به آبجکت فلت شده
    const flatHideData = flattenObject(hideData);

    const CheckHideValues = Object.values(flatHideData).every(
      (value) => value === true,
    );
    hasAnyConflict =
      !CheckHideValues ||
      JSON.stringify(sortData) !== JSON.stringify(initialSort) ||
      !CheckFilterValues;

    setIsDirty(hasConflict);
    setIsAnyDirty(hasAnyConflict);
  }, [hideData, sortData, filterData, initHide, initSort, initFilter]);

  useEffect(() => {
    if (!settingStore) return;
    const filterValues = flatColumns.reduce((acc, column) => {
      if (!column.enableColumnFilter) return acc;
      const storeFilter = settingStore?.[user_id]?.[page_name]?.[table_name]?.[
        "filters"
      ]?.find((filter) => filter.id === column.id);
      if (column.datatype === "array") {
        acc[column.id] = {
          id: column.id,
          value: storeFilter?.value || [],
          filterMode: storeFilter?.filterMode || column.filterMode,
          datatype: column.datatype,
        };
      } else if (column.filterMode === "between") {
        acc[column.id] = {
          id: column.id,
          value: storeFilter?.value || ["", ""],
          filterMode: storeFilter?.filterMode || column.filterMode,
          datatype: column.datatype,
        };
      } else {
        acc[column.id] = {
          id: column.id,
          value: storeFilter?.value || "",
          filterMode: storeFilter?.filterMode || column.filterMode,
          datatype: column.datatype,
        };
      }
      return acc;
    }, {});

    const getHideValues = (columns) => {
      return columns.reduce((acc, column) => {
        const columnId = column.id;
        const storeHide =
          settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"]?.[
            columnId
          ];
        if (column.columns && column.columns.length > 0) {
          acc[columnId] = getHideValues(column.columns);
        } else {
          acc[columnId] = storeHide !== undefined ? storeHide : true;
        }

        return acc;
      }, {});
    };

    const hideValues = getHideValues(columns);
    setHideData(hideValues);
    setInitHide(hideValues);
    setFilterData(filterValues);
    setInitFilter(filterValues);
    setSortData(
      settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] ||
        initialSort,
    );
    setInitSort(
      settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] ||
        initialSort,
    );
    setInitStates(true);
  }, [settingStore]);

  useEffect(() => {
    if (
      JSON.stringify(initFilter) !== JSON.stringify(filterData) ||
      JSON.stringify(initSort) !== JSON.stringify(sortData) ||
      JSON.stringify(initHide) !== JSON.stringify(hideData)
    ) {
      if (!toast.isActive("keep_data", "filtering")) {
        toast(
          <AskForKeepData
            filterData={filterData}
            sortData={sortData}
            hideData={hideData}
            user_id={user_id}
            page_name={page_name}
            table_name={table_name}
            columns={flatColumns}
          />,
          {
            containerId: "filtering",
            toastId: "keep_data",
            className: "filter-toast",
            position: "bottom-left",
            draggable: true,
            autoClose: false,
          },
        );
      } else {
        toast.update("keep_data", {
          containerId: "filtering",
          toastId: "keep_data",
          render: (
            <AskForKeepData
              filterData={filterData}
              sortData={sortData}
              hideData={hideData}
              user_id={user_id}
              page_name={page_name}
              table_name={table_name}
              columns={flatColumns}
            />
          ),
        });
      }
    } else {
      toast.dismiss({ containerId: "datatable" });
    }
  }, [filterData, sortData, hideData]);

  if (!isInitStates) return <LinearProgress sx={{ borderRadius: 2 }} />;

  return (
    <DataTableContext.Provider
      value={{
        filterData,
        setFilterData,
        sortData,
        setSortData,
        hideData,
        setHideData,
        isDirty,
        isAnyDirty,
      }}
    >
      {children}
    </DataTableContext.Provider>
  );
};

export default DataTableProvider;
