import { REDUX_ERROR_PROP_NAME } from '@/modules/@common/Form/constants';

import { getErrorFieldsList } from '@/modules/@common/Form/helpers';

export default function createFormSlice(formReduxKey, initialScheme) {
  const validateSingleField = (schemeFieldName, value, state, ...other) => {
    const field = initialScheme.find((schemeField) => schemeField.fieldName === schemeFieldName);

    return {
      ...field,
      validation: undefined,
      [REDUX_ERROR_PROP_NAME]: field.validation(value, state, ...other),
    };
  };

  const validateFields = (schemeFieldName, state, ...other) => {
    const validation = initialScheme.map((field) =>
      schemeFieldName.includes(field.fieldName)
        ? validateSingleField(
            field.fieldName,
            field.fieldName.split('.').reduce((acc, key) => {
              if (acc !== null && acc !== undefined && Object.prototype.hasOwnProperty.call(acc, key)) {
                return acc[key];
              }
              console.warn(`You try to take value from ${field.fieldName} which doesnt exist in store`);
              return null;
            }, state),
            state,
            ...other,
          )
        : {
            ...field,
            validation: undefined,
            [REDUX_ERROR_PROP_NAME]: false,
          },
    );

    return {
      validation,
      errorList: getErrorFieldsList(validation),
    };
  };

  return {
    validateSingleField,
    validateFields,
    state: {
      [formReduxKey]: {
        scrollField: {
          name: null,
        },
        scheme: validateFields([]).validation,
      },
    },
    actions: {
      setScrollToFieldAction: (state, action) => {
        state[formReduxKey].scrollField = {
          name: action.payload,
        };
      },
      updateValidationSchemeAction: (state, action) => {
        action.payload.forEach((newError) => {
          const findIndex = state[formReduxKey].scheme.findIndex((error) => error.fieldName === newError.fieldName);

          if (findIndex !== -1) {
            const targetError = state[formReduxKey].scheme[findIndex];

            if (Object.entries(targetError).some(([key, value]) => value !== newError[key])) {
              state[formReduxKey].scheme[findIndex] = {
                ...newError,
              };
            }
          }
        });
      },
      removeErrorByFieldNameAction: (state, action) => {
        const [parentKey, ...nestedKeys] = action.payload;
        const current = state[formReduxKey].scheme.find((schemeField) => parentKey === schemeField.fieldName);

        if (current) {
          if (!nestedKeys.length) {
            current[REDUX_ERROR_PROP_NAME] = '';
          } else {
            nestedKeys.reduce((acc, key, index, array) => {
              if (acc !== null && acc !== undefined && Object.prototype.hasOwnProperty.call(acc, key)) {
                if (index >= array.length - 1) {
                  acc[key] = '';

                  return null;
                }

                return acc[key];
              }

              return null;
            }, current[REDUX_ERROR_PROP_NAME]);
          }
        }
      },
    },
  };
}
