'use client';

import React, { useContext, useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';

import { Portal } from './components/portal/portal';
import MakeToggle from './components/make-toggle/make-toggle';
import MakeInput from './components/make-input/make-input';
import MakeSelect from './components/make-select/make-select';
import MakeTextarea from './components/make-textarea/make-textarea';
import {
  IModal,
  IModalField,
  IModalConfigProps,
  IFormField,
} from './interfaces/modal';
import MakeDescription from './components/make-description/make-description';
import { IFieldProps } from './interfaces/field';
import MakeUpload from './components/make-upload/make-upload';
import MakeButton from './components/make-button/make-button';
import { IMakeInput } from './interfaces/make-input';
import { IMakeSelect } from './interfaces/make-select';
import { IMakeTextarea } from './interfaces/make-textarea';
import { IMakeToggle } from './interfaces/make-toggle';
import { IMakeDescription } from './interfaces/make-description';
import { IMakeUpload } from './interfaces/make-upload';
import { IMakeButton } from './interfaces/make-button';
import { ComponentStateContext } from './context/component/component-state';

export const Modal = ({ open, close, config }: IModal) => {
  const { ModalButtonAction, ModalButtonCancel } = useContext(
    ComponentStateContext,
  );
  const [modalReady, setModalReady] = useState<IModalConfigProps | undefined>(
    undefined,
  );
  const [defaultLoaded, setDefaultLoaded] = useState<boolean>(false);

  const {
    control,
    handleSubmit,
    getValues,
    unregister,
    setValue,
    watch,
    trigger,
    reset,
    getFieldState,
  } = useForm();

  const formValueHandler = (element: IFormField) => {
    if (['group', 'upload', 'text'].includes(element.elementType)) return;
    if (!element.defaultValue && element.renderIf) {
      unregister(element.name);
      return;
    }

    const defaultValue = element.defaultValue ?? '';

    const parsedValue: boolean | string | Array<string> | undefined =
      defaultValue === 'true'
        ? true
        : defaultValue === 'false'
          ? false
          : defaultValue;

    setValue(element.name, parsedValue ?? '');
  };

  const autoLoadGroup = (groupFields: Array<IModalField>) => {
    groupFields.forEach((element) => {
      formValueHandler(element as IFormField);
    });
  };

  const autoLoadField = (modalFields: Array<IModalField>) => {
    if (defaultLoaded) return;

    modalFields.forEach((element) => {
      if (element.elementType === 'group') {
        autoLoadGroup(element.groups);
        return;
      }
      formValueHandler(element as IFormField);
    });

    setDefaultLoaded(true);
  };

  const getUseSubmit = (modalConfig: IModalConfigProps): boolean => {
    const useSubmit =
      modalConfig.useSubmit === undefined
        ? true
        : modalConfig.useSubmit === false
          ? false
          : true;

    return useSubmit;
  };

  const getRender = (
    { elementType, ...element }: IModalField,
    index: number,
    isEndOfRender: boolean = false,
  ) => {
    if (isEndOfRender && modalReady)
      setTimeout(() => autoLoadField(modalReady.fields), 200);

    const props: IFieldProps = {
      control,
      watch,
      setValue,
      unregister,
    };

    return elementType === 'input' ? (
      <MakeInput
        {...props}
        key={`modal-input-${index}`}
        element={element as IMakeInput}
      />
    ) : elementType === 'select' ? (
      <MakeSelect
        {...props}
        key={`modal-select-${index}`}
        element={element as IMakeSelect}
      />
    ) : elementType === 'textarea' ? (
      <MakeTextarea
        {...props}
        key={`modal-textarea-${index}`}
        element={element as IMakeTextarea}
      />
    ) : elementType === 'toggle' ? (
      <MakeToggle
        {...props}
        key={`modal-toggle-${index}`}
        element={element as IMakeToggle}
      />
    ) : elementType === 'text' ? (
      <MakeDescription
        {...props}
        key={`modal-text-${index}`}
        element={element as IMakeDescription}
      />
    ) : elementType === 'upload' ? (
      <MakeUpload
        {...props}
        key={`modal-upload-${index}`}
        element={element as IMakeUpload}
      />
    ) : elementType === 'button' ? (
      <MakeButton
        {...props}
        key={`modal-button-${index}`}
        element={element as IMakeButton}
      />
    ) : null;
  };

  const closeHandler = (): void => {
    if (modalReady?.onClose) modalReady.onClose();

    setTimeout(() => {
      setModalReady(undefined);
      setDefaultLoaded(false);
      reset();
      close();
    }, 200);
  };

  const manualSubmit = async (): Promise<void> => {
    const form = getValues();
    const fields = Object.keys(form);
    await trigger(fields);

    const validations: Array<boolean> = fields.map((field) => {
      const { invalid } = getFieldState(field);

      return invalid;
    });

    const result = validations.some((isInvalid) => isInvalid)
      ? undefined
      : form;

    if (!result) return;

    actionHandler({ ...(modalReady?.reservedData ?? {}), ...form });
  };

  const actionHandler = (
    data: Record<string, string | number | object>,
  ): void => {
    modalReady?.out({ ...(modalReady?.reservedData ?? {}), ...data });
    closeHandler();
  };

  useEffect(() => {
    if (open && !modalReady) setModalReady(config);
  }, [config, modalReady, open]);

  if (!modalReady) return null;

  return (
    <Portal closeTime={200} portalOpen={open} portalTag={'#modal-portal'}>
      <div
        className="rounded bg-white relative w-auto h-auto min-h-[200px] min-w-[500px]"
        style={modalReady.style}
      >
        <form
          className="flex flex-col p-4 gap-4"
          autoComplete="off"
          onSubmit={handleSubmit(actionHandler)}
        >
          <h2 className="text-bold text-center border-b pb-4 font-semibold">
            {modalReady.title}
          </h2>
          <div
            className="flex flex-col gap-4 py-4"
            style={{
              overflowY: modalReady.overFlowBody ? 'auto' : undefined,
              height: modalReady.overFlowBody,
              minHeight: modalReady.minHeightBody,
            }}
          >
            {modalReady.fields.map((element, index) => {
              const isEndOfRender: boolean =
                index + 1 === modalReady.fields.length;

              if (element.elementType === 'group') {
                return (
                  <div
                    key={`modal-group-${index}`}
                    className="flex flex-col w-full gap-2"
                  >
                    {element.title && (
                      <h3 className="font-bold border-b-2 pb-2 mb-2">
                        {element.title}
                      </h3>
                    )}
                    <div
                      key={`modal-group-${index}`}
                      className="flex gap-4 w-full"
                      style={element.style}
                    >
                      {element.groups
                        .filter((sub) =>
                          [
                            'input',
                            'select',
                            'toggle',
                            'multiselect',
                            'upload',
                            'button',
                            'autocomplete',
                          ].includes(sub.elementType),
                        )
                        .map((sub, subIndex) =>
                          getRender(sub, index + subIndex, isEndOfRender),
                        )}
                    </div>
                  </div>
                );
              } else {
                return getRender(element, index, isEndOfRender);
              }
            })}
          </div>
          <div
            className="flex gap-4 items-center justify-center border-t p-2"
            style={modalReady?.actions.containerStyle}
          >
            {modalReady.actions.cancel && (
              <ModalButtonCancel
                {...modalReady.actions.cancel}
                onClick={closeHandler}
              />
            )}
            {getUseSubmit(modalReady) ? (
              <ModalButtonAction {...modalReady.actions.action} type="submit" />
            ) : (
              <ModalButtonAction
                {...modalReady.actions.action}
                onClick={manualSubmit}
                type="button"
              />
            )}
          </div>
        </form>
      </div>
    </Portal>
  );
};

export default Modal;
