import React, { useEffect, useMemo, useRef } from 'react';
import { useSelector } from 'react-redux';
import classNames from 'clsx';

import { SCROLL_POSITION_DELTA } from '@/modules/@common/Form/constants';
import { SIZE_MEDIUM, SIZE_SMALL } from '@/mui/constants';

import { FormContext, getScrollOffsetToChild } from '../helpers/hooks';

import { LinearProgress } from '@/mui/components';

import styles from './Form.module.scss';

type FormProps = {
  size?: typeof SIZE_SMALL | typeof SIZE_MEDIUM;
  scrollFieldSelector?: (state: RootState) => { name: string };
  disabled?: boolean;
  loading?: boolean;
  children: React.ReactNode;
};

function Form({
  size = SIZE_SMALL,
  scrollFieldSelector = () => ({ name: '' }),
  disabled = false,
  loading = false,
  children,
}: FormProps) {
  const formRef = useRef<HTMLFormElement | null>(null);
  const targetField = useSelector(scrollFieldSelector);

  useEffect(() => {
    let timer: NodeJS.Timeout | null = null;
    const form = formRef.current;
    const field = targetField.name ? (form?.elements.namedItem(targetField.name) as HTMLElement) : null;

    if (form && field) {
      timer = setTimeout(() => {
        form.scroll({
          top: getScrollOffsetToChild(field) - SCROLL_POSITION_DELTA,
          left: 0,
          behavior: 'smooth',
        });
      }, 0);

      return () => {
        if (timer) {
          clearTimeout(timer);
        }
      };
    }

    return () => {
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, [targetField]);

  const formOptions = useMemo(
    () => ({
      size,
    }),
    [size],
  );

  return (
    <FormContext.Provider value={formOptions}>
      <form
        ref={formRef}
        className={classNames(styles.Wrapper, {
          [styles.Wrapper___disabled]: disabled,
          [styles.Wrapper___loading]: loading,
        })}
      >
        {!!loading && <LinearProgress color="primary" className={styles.Loading} />}
        {children}
      </form>
    </FormContext.Provider>
  );
}

export default Form;
