import { useEffect, useMemo, useState } from "react";
import {
  CompositeFilterDescriptor,
  DataResult,
  FilterDescriptor,
  State,
  process,
} from "@progress/kendo-data-query";
import {
  GridColumnReorderEvent,
  GridColumnResizeEvent,
  GridFilterChangeEvent,
  GridHeaderSelectionChangeEvent,
  GridSelectionChangeEvent,
  GridSortChangeEvent,
  GridSortSettings,
} from "@progress/kendo-react-grid";
import { Pager, PageChangeEvent, SelectDescriptor } from "@progress/kendo-react-data-tools";
import GridWidgetView, { Action } from "./GridWidgetView";
import { GridDataState, GridProps } from "./types";
import {
  handleSelectionChange,
  handleHeaderSelectionChange,
  unMarkAllDataAsUnSelected,
  markAllDataAsSelected,
  deserializedGroupFilelds,
} from "./gridHandlers";
import _, { get } from "lodash";
import { getUniqueId } from "../../../helper";

export const initialLocalFilters: CompositeFilterDescriptor = {
  logic: "and",
  filters: [],
};

const GridWidget = (props: GridProps) => {
  const [select, setSelect] = useState<SelectDescriptor>({});
  const [activeColumns, setActiveColumns] = useState<any[]>([]);
  const [baseData, setBaseData] = useState<GridDataState>({
    records: [],
    total: 0,
  });

  useEffect(() => {
    const defaultColumns = [...(props.columns ?? [])].sort(
      (a, b) => (a.order ?? 0) - (b.order ?? 0)
    );
    const updatedUiElementGroupData = {
      ...props.uiElementGroupData,
      processing: false,
      localSearch: initialLocalFilters,
      sort: props.sortConfig?.defaultSortFields ?? [],
      defaultSort: props.sortConfig?.defaultSortFields ?? [],
      globalFilters: props.filterConfig?.defaultFilterCriteria,
      defaultGroups: props.groupConfig?.defaultGroupFields ?? [],
      pagination: props.paginationConfig?.defaultPagination,
      defaultPagination: props.paginationConfig?.defaultPagination,
      defaultColumns,
      lazyLoad: props.lazyLoading,
      enableDataLoading: false,
    };

    props.onModelUpdate?.(
      null,
      props.config.uiElementGroupId,
      _.cloneDeep(updatedUiElementGroupData)
    );
    return () => {
      props?.onModelUpdate?.(null, props.screenDataField ?? "", {
        records: [],
        total: 0,
      });
    };
  }, []);

  useEffect(() => {
    setBaseData({
      records: props.value?.records ?? [],
      total: props.lazyLoading
        ? props.value?.total ?? 0
        : props.value?.records?.length ?? 0,
    });
  }, [JSON.stringify(props.value)]);

  useEffect(() => {
    let columns = [];
    const chooserColumns =
      props?.uiElementGroupData?.setting?.columnChooser?.appliedColumns;

    if (chooserColumns?.length) {
      chooserColumns?.map((c: any) => {
        const column = _.cloneDeep(
          props.columns?.find((column: any) => c.id === column.id)
        );
        if (column) {
          column.locked = c.isFreezed;
          column.order = c.order;
          column.selected = c.selected;
          if (c.width) {
            column.width = c.width;
          }
          columns.push(column);
        }
      });
    } else {
      columns =
        props?.uiElementGroupData?.defaultColumns?.filter(
          (column: any) => column.selected === true
        ) ?? [];
    }

    const sortedColumns = columns?.sort((a: any, b: any) => a.order - b.order);
    setActiveColumns(sortedColumns);
  }, [
    JSON.stringify(props?.uiElementGroupData?.defaultColumns),
    JSON.stringify(
      props?.uiElementGroupData?.setting?.columnChooser?.appliedColumns
    ),
  ]);

  useEffect(() => {
    if (
      props?.uiElementGroupData?.processing === false &&
      props.onScreenDataLoad
    ) {
      props.onScreenDataLoad?.(resultHandler);
    }
  }, [
    JSON.stringify(props?.uiElementGroupData?.pagination),
    JSON.stringify(props?.uiElementGroupData?.sort),
    JSON.stringify(props?.uiElementGroupData?.localSearch),
    props?.uiElementGroupData?.processing,
  ]);

  const dataResult = useMemo<DataResult>(() => {
    let applicableDataState: State = {};
    if (!props.onScreenDataLoad) {
      applicableDataState.group = deserializedGroupFilelds(
        props?.uiElementGroupData?.groupedBy?.appliedGroups ?? [],
        props?.uiElementGroupData?.defaultGroups
      );
    } else {
      applicableDataState.skip = props?.uiElementGroupData?.pagination?.skip;
      applicableDataState.take = props?.uiElementGroupData?.pagination?.take;
      applicableDataState.group = props?.uiElementGroupData?.defaultGroups;
      applicableDataState.sort = props?.uiElementGroupData?.sort;
    }
    return process(baseData.records, applicableDataState);
  }, [
    JSON.stringify(baseData.records),
    JSON.stringify(props?.uiElementGroupData?.groupedBy?.appliedGroups),
  ]);

  const getEffectiveLocalFilters = (
    name: string,
    value: any
  ): Record<string, any> => {
    let effectiveFilters: Record<string, any> =
      props?.uiElementGroupData?.localSearch ?? initialLocalFilters;

    const position = effectiveFilters.filters.findIndex((f: any) => {
      return (f as FilterDescriptor).field === name;
    });

    if (position === -1) {
      effectiveFilters = {
        ...effectiveFilters,
        filters: [
          ...effectiveFilters.filters,
          {
            field: name,
            operator: "contains",
            value: value || "",
            id: "LCS__" + getUniqueId(),
          },
        ],
      };
    } else {
      if (value) {
        effectiveFilters = {
          ...effectiveFilters,
          filters: effectiveFilters.filters.map((item: any, index: number) =>
            index === position
              ? {
                field: name,
                operator: "contains",
                value: value || "",
                id: item.id,
              }
              : item
          ),
        };
      } else {
        effectiveFilters = {
          ...effectiveFilters,
          filters: effectiveFilters.filters.filter(
            (f: any, index: number) => index !== position
          ),
        };
      }
    }
    return effectiveFilters;
  };

  const resultHandler = (response: any) => {
    props.onModelUpdate?.(null, props.screenDataField ?? "", response);
  };

  const onFilterChange = (event: GridFilterChangeEvent) => {
    debugger;
  };

  const onSelectionChange = (event: GridSelectionChangeEvent) => {
    setSelect(event.select);
  };

  const onHeaderSelectionChange = (event: GridHeaderSelectionChangeEvent) => {
    setSelect(event.select);
  };

  const onColumnResize = (event: GridColumnResizeEvent) => {
    if (event.end) {
      if (props?.uiElementGroupData?.setting) {
        const modifiedColumns =
          props?.uiElementGroupData?.setting?.columnChooser?.appliedColumns?.map(
            (c: any) => {
              const newColumn = _.cloneDeep(c);
              if (newColumn.id === event.targetColumnId) {
                newColumn.width = event.newWidth;
              }
              return newColumn;
            }
          );
        const updatedColumnChooser = {
          ...props.uiElementGroupData.setting.columnChooser,
          selectedColumns: _.cloneDeep(modifiedColumns),
          appliedColumns: _.cloneDeep(modifiedColumns),
        };

        const updatedSetting = {
          ...props.uiElementGroupData.setting,
          columnChooser: updatedColumnChooser,
        };

        const updatedUiElementGroupData = {
          ...props.uiElementGroupData,
          setting: updatedSetting,
        };

        props?.onModelUpdate?.(
          null,
          props?.config?.uiElementGroupId,
          updatedUiElementGroupData
        );
      } else {
        const modifiedColumns = _.cloneDeep(
          props?.uiElementGroupData?.defaultColumns?.map((c: any) => {
            if (c.id === event.targetColumnId) {
              c.width = event.newWidth;
            }
            return c;
          })
        );
        let uiElementsColumns = props.uiElementGroupData ?? {};
        uiElementsColumns = {
          ...uiElementsColumns,
          defaultColumns: modifiedColumns,
        };
        props?.onModelUpdate?.(
          null,
          props?.config?.uiElementGroupId,
          uiElementsColumns
        );
      }
    }
  };

  const onColumnReorder = (event: GridColumnReorderEvent) => {
    const reOrderedColumns = event.columns.sort(
      (a, b) => (a?.orderIndex ?? 0) - (b?.orderIndex ?? 0)
    );
    if (props?.uiElementGroupData?.setting) {
      const modifiedColumns: any[] = [];
      reOrderedColumns.map((r) => {
        const chooserColumn = _.cloneDeep(
          props?.uiElementGroupData?.setting?.columnChooser?.selectedColumns?.find(
            (a: any) => a.id === r.id
          )
        );
        if (chooserColumn) {
          chooserColumn.order = r.orderIndex;
          modifiedColumns.push(chooserColumn);
        }
      });

      const updatedColumnChooser = {
        ...props.uiElementGroupData?.setting?.columnChooser,
        selectedColumns: _.cloneDeep(modifiedColumns),
        appliedColumns: _.cloneDeep(modifiedColumns),
      };

      const updatedSetting = {
        ...props.uiElementGroupData.setting,
        columnChooser: updatedColumnChooser,
      };

      const updatedUiElementGroupData = {
        ...props.uiElementGroupData,
        setting: updatedSetting,
      };
      props?.onModelUpdate?.(
        null,
        props?.config?.uiElementGroupId,
        updatedUiElementGroupData
      );
    }
  };

  const onSortChange = (event: GridSortChangeEvent) => {
    let uiElementGroupData = props?.uiElementGroupData ?? {};

    uiElementGroupData = {
      ...uiElementGroupData,
      sort: event.sort,
    };

    props?.onModelUpdate?.(
      null,
      props?.config?.uiElementGroupId,
      uiElementGroupData
    );
  };

  const onPageChange = (event: PageChangeEvent) => {
    const { skip, take } = event;
    let uiElementGroupData = props?.uiElementGroupData ?? {};

    uiElementGroupData = {
      ...uiElementGroupData,
      pagination: {
        ...uiElementGroupData.pagination,
        skip,
        take,
      },
    };

    props?.onModelUpdate?.(
      null,
      props?.config?.uiElementGroupId,
      uiElementGroupData
    );
  };

  const onLocalSearchChange = ({ name, value }: any) => {
    const effectiveFilters = getEffectiveLocalFilters(name, value);
    const appliedLocalSearch: { criteria: string; filters: any[] } = {
      criteria: "AND",
      filters: [],
    };

    let uiElementGroupData = _.cloneDeep(props?.uiElementGroupData ?? {});
    effectiveFilters?.filters?.map((filter: any) => {
      appliedLocalSearch.filters.push({
        id: filter.id,
        field: filter.field,
        value: filter.value,
      });
    });

    uiElementGroupData = {
      ...uiElementGroupData,
      localSearch: appliedLocalSearch,
      pagination: { ...uiElementGroupData.pagination, skip: 0 },
    };

    props?.onModelUpdate?.(
      null,
      props?.config?.uiElementGroupId,
      uiElementGroupData
    );
  };
  const handleClick = (cellProps: any, e: any) => {
    props.navigate && props.navigate(null, cellProps.dataItem.id);
  };

  const onAllMarked = () => {
    let selectedRows = {};
    baseData.records.map((r) => {
      selectedRows = { ...selectedRows, [r[props.dataItemKey ?? "id"]]: true };
    });
    setSelect(selectedRows);
    //  markAllDataAsSelected(baseData, props.selectedField, resultHandler);
  };
  const onAllUnmarked = () => {
    let selectedRows = {};
    baseData.records.map((r) => {
      selectedRows = { ...selectedRows, [r[props.dataItemKey ?? "id"]]: false };
    });
    setSelect(selectedRows);
    // unMarkAllDataAsUnSelected(baseData, props.selectedField, resultHandler);
  };

  const headerActionCallback = (needLoadData?: boolean) => {
    setSelect({});
    if (needLoadData) {
      let uiElementGroupData = props?.uiElementGroupData ?? {};

      uiElementGroupData = {
        ...uiElementGroupData,
        needLoadData: !(uiElementGroupData?.needLoadData ?? needLoadData),
        pagination: {
          ...uiElementGroupData.pagination,
          skip: 0
        },
      };

      props?.onModelUpdate?.(
        null,
        props?.config?.uiElementGroupId,
        uiElementGroupData
      );
    }
  };

  const handleConfirm = async (
    invokeAction: any,
    selectedData: any,
    refresh: boolean
  ) => {
    await invokeAction(null, selectedData);
    headerActionCallback(refresh);
  };

  const handleHeaderAction = (
    callBack: any,
    screenDataField: string,
    action: Action,
    event: any
  ) => {
    const selectedData = baseData.records.filter(
      (r) => select[r[props.dataItemKey ?? "id"]] === true
    );
    const invokeAction = props.dynamicEvents?.[action.actionName];

    props.onModelUpdate?.(null, action.targetScreenDataField, {
      visibleMode: "SHOW",
      onConfirm: () => {
        handleConfirm(invokeAction, selectedData, action.refresh);
      },
      onCancel: () => {
        onAllUnmarked();
      },
      selectedData,
    });
  };
  return (
    <>
      <GridWidgetView
        select={select}
        dataItemKey={props.dataItemKey}
        widgetStyle={props.widgetStyle}
        id={props.id}
        data={dataResult}
        selectedCount={Object.values(select).filter((s) => s === true).length}
        sortable={
          {
            mode: props.sortConfig?.sortMode,
            allowUnsort: props.sortConfig?.sortable,
          } as GridSortSettings
        }
        sort={
          props?.uiElementGroupData?.sort ??
          props?.uiElementGroupData?.defaultSort
        }
        filterable={props.filterConfig?.filterable}
        filter={props?.uiElementGroupData?.globalFilters}
        groupable={props.groupConfig?.groupable}
        group={deserializedGroupFilelds(
          props?.uiElementGroupData?.groupedBy?.appliedGroups ?? [],
          props?.uiElementGroupData?.defaultGroups
        )}
        selectedField={props.selectedField}
        columns={activeColumns}
        headerActionBar={props.headerActionBar}
        onFilterChange={onFilterChange}
        onSelectionChange={onSelectionChange}
        onHeaderSelectionChange={onHeaderSelectionChange}
        onColumnResize={onColumnResize}
        onColumnReorder={onColumnReorder}
        onSortChange={onSortChange}
        onLocalSearchChange={onLocalSearchChange}
        columnSearchValues={
          props?.uiElementGroupData?.localSearch ?? initialLocalFilters
        }
        onAllMarked={onAllMarked}
        onAllUnmarked={onAllUnmarked}
        handleClick={handleClick}
        handleHeaderAction={handleHeaderAction}
      />
      {props.paginationConfig?.pageable && (
        <Pager
          skip={
            props?.uiElementGroupData?.pagination?.skip ??
            props?.uiElementGroupData?.defaultPagination?.skip ??
            0
          }
          take={
            props?.uiElementGroupData?.pagination?.take ??
            props?.uiElementGroupData?.defaultPagination?.take ??
            baseData?.total
          }
          total={baseData?.total}
          buttonCount={props.paginationConfig.paginationInfo?.buttonCount}
          info={props.paginationConfig.paginationInfo?.info}
          pageSizes={props.paginationConfig.paginationInfo?.pageSizes}
          previousNext={props.paginationConfig.paginationInfo?.previousNext}
          onPageChange={onPageChange}
          type={props.paginationConfig.paginationInfo?.paginationType}
        />
      )}
    </>
  );
};

export default GridWidget;
