import { useLayoutEffect, useRef } from 'react';
import { FormHandles } from '@unform/core';
import isPromise from 'is-promise';
import { useImmer } from 'use-immer';
import { setErrorUnFormWithYup } from '../../services/utils.service';
import { useView } from '../useView/index';
import { IStatusInfoViewForm, IUseViewFormProps, IViewFormResponse } from './useViewForm.interfaces';

export function useViewForm<R extends any>({
   id,
   resolveGet,
   resolveCreate,
   resolveUpdate,
   onErrorValidate,
   onSuccess,
   onFailed,
   yupValidateSchema,
   onValidateFormData,
   handleFormData,
   resolves = {},
   firstLoad = true,
}: IUseViewFormProps): IViewFormResponse {
   // Se houver ID, faz primeira request
   const resolvesForm = { ...resolves };
   if (id) resolvesForm.resource = resolveGet;

   const {
      statusInfo,
      setStatusInfo,
      registerOnInit,
      registerOnInitError,
      getParamsResolve,
      registerResolveParams,
      $destroy,
      reloadPage,
   } = useView({
      resolves: resolvesForm,
      firstLoad,
   });

   const formRef = useRef<FormHandles>();

   const [resource, setResource] = useImmer<any>({});

   /**
    * Valores iniciais
    */
   useLayoutEffect(() => {
      setStatusInfo({
         saving: false,
         notFound: false,
      });
   }, []);

   /**
    * Adicionar id na request do items
    *
    * handleRequestBody
    */
   registerResolveParams('resource', () => id);

   /**
    * Resgatar dados da inicialização
    *
    * Resgatar resolve items para definir items
    */
   registerOnInit((res) => {
      if (res.resource) {
         setResource((draft) => res.resource);
      }
   });

   /**
    *
    * @param data
    */
   async function validateFormData(data: any): Promise<boolean> {
      let valid = true;

      // Validação Yup
      if (yupValidateSchema) {
         valid = valid && (await setErrorUnFormWithYup(formRef, data, yupValidateSchema));
      }

      // Validação Custom
      if (onValidateFormData) {
         valid = valid && onValidateFormData(data);
      }

      return valid;
   }

   async function onSubmitForm(data: any): Promise<void> {
      let newData = data;

      if (handleFormData) {
         if (isPromise(handleFormData(data))) {
            newData = await handleFormData(data);
         } else {
            newData = handleFormData(data);
         }
      }

      if (!(await validateFormData(newData))) {
         if (onErrorValidate) onErrorValidate();
         return;
      }

      setStatusInfo({
         saving: true,
      });

      if (!id) {
         if (resolveCreate) {
            resolveCreate(newData).subscribe(
               (response: any) => {
                  setStatusInfo({
                     saving: false,
                  });

                  if (onSuccess) onSuccess(true, response);
               },
               (err) => {
                  setStatusInfo({
                     saving: false,
                  });

                  if (onFailed) onFailed(true, err);
               },
            );
         } else {
            setStatusInfo({
               saving: false,
            });
         }
      } else if (resolveUpdate) {
         resolveUpdate(newData).subscribe(
            (response: any) => {
               setStatusInfo({
                  saving: false,
               });
               if (onSuccess) onSuccess(false, response);
            },
            (err) => {
               setStatusInfo({
                  saving: false,
               });
               if (onFailed) onFailed(false, err);
            },
         );
      } else {
         setStatusInfo({
            saving: false,
         });
      }
   }

   function submit(): void {
      formRef.current.submitForm();
   }

   return {
      ...(statusInfo as IStatusInfoViewForm),
      statusInfo,
      setStatusInfo,
      registerOnInit,
      registerOnInitError,
      getParamsResolve,
      registerResolveParams,
      $destroy,
      reloadPage,
      //
      resource,
      formRef,
      onSubmitForm,
      submit,
   };
}
