/* eslint-disable @typescript-eslint/no-explicit-any */
import { get, isEqual, set } from "lodash-es";
import {
  FC,
  useCallback,
  useEffect,
  useMemo,
  useRef,
} from "react";
import { useDispatch, useSelector, useStore } from "react-redux";
import {
  getIsIMPAKTEditMode,
  getSelectedScreen,
} from "@/redux/config/configSelector";
import { getComponentMap } from "@/redux/currentApp/components/componentsSelector";
import { componentsActions } from "@/redux/currentApp/components/componentsSlice";
import { getExecutionResult } from "@/redux/currentApp/executionTree/executionSelector";
import { evaluateDynamicString } from "@/utils/evaluateDynamicString";
import { IMPAKTAPPSEditorRuntimePropsCollectorInstance } from "@/utils/executionTreeHelper/runtimePropsCollector";
import { FormWidgetProps } from "./interface";
// import { formBodyStyle, formContainerStyle } from "./style";
import { FORM_CAN_BIND_WIDGET_TYPE } from "./widgetConfig";
import { isObject } from "@/redux/utils";
import { ComponentMapNode } from "@/utils/generators/interface";
import { ContainerProps } from "../ContainerWidget/interface";
// import { updateGridPositions } from "../CSSGrid/utils";
import { BasicContainerConfig } from "../BasicContainer/BasicContainer";
import { newGenerateChildrenComponentNode } from "@/utils/generators/generateComponentNode";
import _ from "lodash";
import GridChild from "../CSSGrid/GridChild";
import { v4 } from "uuid";
import { gridDisplayNameCss, gridStyle } from "../CSSGrid/style";
import { useTheme } from "@mui/material";

function getLikeInputChildrenNode(
  componentNodeDisplayName: string,
  componentNodeResult: ComponentMapNode[],
  components: Record<string, ComponentMapNode>,
  hasForm: boolean
) {
  const componentNode = components[componentNodeDisplayName];
  if (
    (componentNode.containerType !== "EDITOR_DOT_PANEL" &&
      FORM_CAN_BIND_WIDGET_TYPE.has(componentNode.type)) ||
    (hasForm && componentNode.type === "FORM_WIDGET")
  ) {
    componentNodeResult.push(componentNode);
    if (Array.isArray(componentNode.childrenNode)) {
      componentNode.childrenNode.forEach((childDisplayName) => {
        getLikeInputChildrenNode(
          childDisplayName,
          componentNodeResult,
          components,
          hasForm
        );
      });
    }
  } else {
    if (Array.isArray(componentNode.childrenNode)) {
      componentNode.childrenNode.forEach((childDisplayName) => {
        getLikeInputChildrenNode(
          childDisplayName,
          componentNodeResult,
          components,
          hasForm
        );
      });
    }
  }
}
interface Form extends FormWidgetProps, ContainerProps {}
export const FormWidget: FC<Form> = (props) => {
  const {
    childrenNode: childrenNodeDisplayNames,
    disabled,
    displayName,
    disabledSubmit,
    resetAfterSuccessful,
    validateInputsOnSubmit,
    formData: propsFormData,
    updateComponentRuntimeProps,
    deleteComponentRuntimeProps,
    handleUpdateMultiExecutionResult,
    handleUpdateOriginalDSLMultiAttr,
    triggerEventHandler,
    Mobile,
    Tablet,
    Desktop,
  } = props;
  const Screen: any = useSelector(getSelectedScreen);
  const isEditMode = useSelector(getIsIMPAKTEditMode);
  const prevDisabled = useRef<boolean>(disabled);
  const executionResult = useSelector(getExecutionResult);
  const components = useSelector(getComponentMap);
  const dispatch = useDispatch();
 const store = useStore()
  const allLikeInputWithFormChildrenNodeDisplayName = useMemo(() => {
    const componentNodeResult: ComponentMapNode[] = [];
    childrenNodeDisplayNames.forEach((node) => {
      getLikeInputChildrenNode(node, componentNodeResult, components, true);
    });
    return componentNodeResult.map((node) => node.displayName);
  }, [childrenNodeDisplayNames, components]);

  const allLikeInputChildrenNode = useMemo(() => {
    const componentNodeResult: ComponentMapNode[] = [];
    childrenNodeDisplayNames.forEach((node) => {
      getLikeInputChildrenNode(node, componentNodeResult, components, false);
    });
    return componentNodeResult;
  }, [childrenNodeDisplayNames, components]);

  const allLikeInputChildrenNodeDisplayName = useMemo(() => {
    return allLikeInputChildrenNode.map((node) => node.displayName);
  }, [allLikeInputChildrenNode]);

  const allLikeInputChildrenNodeRealProps = useMemo(() => {
    return allLikeInputChildrenNodeDisplayName.map((name) => {
      const widgetProps = get(executionResult, name, {});
      return {
        displayName: name,
        ...widgetProps,
      };
    });
  }, [allLikeInputChildrenNodeDisplayName, executionResult]);

  const formDataKeyMapProps = useMemo(() => {
    const map: Record<string, any> = {};
    allLikeInputChildrenNodeRealProps.forEach((prop) => {
      set(map, prop.formDataKey || prop.displayName, prop);
    });
    return map;
  }, [allLikeInputChildrenNodeRealProps]);

  const formData = useMemo(() => {
    const data: Record<string, any> = {};
    allLikeInputChildrenNodeRealProps.forEach((prop) => {
      set(data, prop.formDataKey || prop.displayName, prop.value);
    });
    return data;
  }, [allLikeInputChildrenNodeRealProps]);

  useEffect(() => {
    if (!isEqual(formData, propsFormData)) {
      handleUpdateMultiExecutionResult?.([
        {
          displayName,
          value: {
            formData: formData,
          },
        },
      ]);
    }
  }, [
    dispatch,
    displayName,
    formData,
    handleUpdateMultiExecutionResult,
    propsFormData,
  ]);

  useEffect(() => {
    if (prevDisabled.current !== disabled) {
      const updateArray = allLikeInputWithFormChildrenNodeDisplayName.map(
        (displayName) => {
          return {
            displayName,
            updateSlice: {
              disabled:
                typeof disabled === "undefined" || disabled == false
                  ? ""
                  : `{{${disabled}}}`,
            },
          };
        }
      );
      dispatch(componentsActions.updateMultiComponentPropsReducer(updateArray));
    }
    prevDisabled.current = disabled;
  }, [
    disabled,
    childrenNodeDisplayNames,
    allLikeInputWithFormChildrenNodeDisplayName,
    dispatch,
  ]);

  const handleOnInvalid = useCallback(() => {
    triggerEventHandler("invalid");
  }, [triggerEventHandler]);

  const handleOnValidate = useCallback(() => {
    const finalContext =
      IMPAKTAPPSEditorRuntimePropsCollectorInstance.getCurrentPageCalcContext({},store);
    allLikeInputChildrenNode.forEach((node) => {
      try {
        return evaluateDynamicString(
          "events",
          `{{${node.displayName}.validate()}}`,
          finalContext
        );
      } catch (e) {
        return false;
      }
    });
  }, [allLikeInputChildrenNode]);

  const handleSetValue = useCallback(
    (value: Record<string, any>) => {
      const keys = Object.keys(value);
      const updateSlice: {
        displayName: string;
        value: {
          value: string;
        };
      }[] = [];

      keys.forEach((key) => {
        const realDisplayName = get(formDataKeyMapProps, key, null);
        if (realDisplayName) {
          updateSlice.push({
            displayName: key,
            value: {
              value: value[key],
            },
          });
        }
      });
      if (updateSlice.length > 0) {
        handleUpdateMultiExecutionResult?.(updateSlice);
      }
    },
    [formDataKeyMapProps, handleUpdateMultiExecutionResult]
  );

  const handleOnReset = useCallback(() => {
    const allUpdate = allLikeInputChildrenNode.map((node) => {
      return {
        displayName: node.displayName,
        value: {
          value: node.props!.value,
          validateMessage: "",
        },
      };
    });
    handleUpdateMultiExecutionResult?.(allUpdate);
  }, [allLikeInputChildrenNode, handleUpdateMultiExecutionResult]);

  const handleOnSubmit = useCallback(() => {
    if (disabledSubmit || disabled) return;
    if (validateInputsOnSubmit) {
      const finalContext =
        IMPAKTAPPSEditorRuntimePropsCollectorInstance.getCurrentPageCalcContext({},store);
      const validateResult = allLikeInputChildrenNode.every((node) => {
        try {
          const validateFunc = get(
            finalContext,
            `${node.displayName}.validate`
          ) as unknown;
          if (typeof validateFunc === "function") {
            return !validateFunc();
          }
          return false;
        } catch (e) {
          return false;
        }
      });
      if (!validateResult) {
        handleOnInvalid();
        return;
      }
    }
    triggerEventHandler("submit");
    if (resetAfterSuccessful) {
      handleOnReset();
    }
  }, [
    allLikeInputChildrenNode,
    disabled,
    disabledSubmit,
    handleOnInvalid,
    handleOnReset,
    resetAfterSuccessful,
    triggerEventHandler,
    validateInputsOnSubmit,
  ]);
  useEffect(() => {
    updateComponentRuntimeProps({
      submit: handleOnSubmit,
      invalid: handleOnInvalid,
      reset: handleOnReset,
      setValue: (value: Record<string, any>) => {
        if (isObject(value)) {
          handleSetValue(value);
        }
      },
      validate: handleOnValidate,
    });
    return () => {
      deleteComponentRuntimeProps();
    };
  }, [
    deleteComponentRuntimeProps,
    handleOnInvalid,
    handleOnReset,
    handleOnSubmit,
    handleOnValidate,
    handleSetValue,
    updateComponentRuntimeProps,
  ]);
  const theme = useTheme()
  const componentsMap: any = useSelector(getComponentMap);
  const ChildNodesMap = useMemo(
    () =>
      componentsMap[displayName].childrenNode.map((e) => {
        return componentsMap[e];
      }),
    [componentsMap, displayName]
  );

  const handleAddNewRow = useCallback(
    (ComponentName, componentIndex) => {
      const componentActualCount: number =
        ComponentName === "Row" ? Desktop.columnSize || 4 : 1;
      const newItem = [];
      for (let i = 0; i < componentActualCount; i++) {
        newItem.push({
          id: v4(),
          key: `view ${childrenNodeDisplayNames.length + 1 + i}`,
          label: `view ${childrenNodeDisplayNames.length + +1 + i}`,
          rowSpan: 1,
          columnSpan: 1,
        });
      }
      const previosArr = [];
      const arr1 = [];
      newItem.map((e: any) => {
        const newChildrenNodes = newGenerateChildrenComponentNode(
          BasicContainerConfig,
          displayName
        );
        handleUpdateOriginalDSLMultiAttr?.({
          ["viewList"]: [...ChildNodesMap, ...previosArr, e],
        });
        previosArr.push(e);
        arr1.push(newChildrenNodes);
      });
      dispatch(componentsActions.addComponentReducer(arr1));
      const childNodesArray = _.cloneDeep(childrenNodeDisplayNames);
      const newChilds: string[] = arr1.map((e) => e.displayName);
      childNodesArray.splice(componentIndex, 0, ...newChilds);
      dispatch(
        componentsActions.sortComponentNodeChildrenReducer({
          parentDisplayName: displayName,
          newChildrenNode: childNodesArray,
        })
      );
    },
    [
      Desktop.columnSize,
      dispatch,
      childrenNodeDisplayNames,
      displayName,
      handleUpdateOriginalDSLMultiAttr,
      ChildNodesMap,
    ]
  ); 
  const containerSTyle = useMemo(() => {
    return gridStyle(Mobile, Tablet, Desktop, Screen, isEditMode,theme);
  }, [Desktop, Mobile, Screen, Tablet, isEditMode, theme]);
  return (
    <div css={containerSTyle} key={`${displayName}-Wrapper`}>
      {isEditMode && <div css={gridDisplayNameCss(theme)}>{displayName}</div>}
      {ChildNodesMap.map((gridChildConfig: any, i: number) => {
        return (
          <GridChild
            config={gridChildConfig}
            configArray={ChildNodesMap}
            index={i}
            handleAddNewRow={handleAddNewRow}
            childrenNode={props.childrenNode}
            attrPath={props.attrPath}
            handleUpdateOriginalDSLMultiAttr={
              props.handleUpdateOriginalDSLMultiAttr
            }
          />
        );
      })}
    </div>
  );
};

FormWidget.displayName = "FormWidget";
export default FormWidget;
{
  /* <RenderChildrenCanvas
          displayName={childrenNodeDisplayNames[1]}
          columnNumber={2}
          handleUpdateHeight={handleUpdateHeight}
          canResizeCanvas={false}
          containerPadding={"none"}
          key={childrenNodeDisplayNames[1] + "canvas"}
          gridContainer={true}
        /> */
}
// {isMouseHover && isEditMode && (
//   <div css={applyXDirectionDashedLineStyle(false, true, false)} />
// )}
// </div>
// </div>
