import { yupResolver } from '@hookform/resolvers/yup'
import {
  Alert,
  Box,
  Button,
  ButtonProps,
  CircularProgress,
  Typography,
} from '@mui/material'

import { ReactNode, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useMutation, useQueryClient } from 'react-query'
import { toast } from 'react-toastify'
import axios, { axiosErrorToast } from '../../config/axios'
import RenderForm, { RenderFormProps, generateYupSchema } from './RenderForm'
import { useErrorModal } from '../ErrorModalWrapper/ErrorModalWrapper'

const makePostRequest = async ({
  endpoint,
  postBody,
}: {
  endpoint: string
  postBody: any
}) => {
  const method = postBody?.id ? 'PUT' : 'POST'
  const url = postBody?.id ? `${endpoint}/${postBody?.id}` : endpoint
  return await axios({
    url,
    method,
    data: postBody,
  })
}

interface FormProps extends Omit<RenderFormProps, 'control'> {
  buttonProps?: ButtonProps
  submitBtn?: { label?: ReactNode }
  cancelBtn?: { label?: ReactNode }
  onSubmit?: (formData) => any
  onCancel?: () => void
  endPoint?: string
  defaultValues?: any
  refetchKey?: string
  onSuccess?: () => void
  successToastMessage?: string
}

export default function Form({
  submitBtn = { label: 'Submit' },
  cancelBtn = { label: 'Cancel' },
  buttonProps,
  onSubmit = () => {},
  endPoint,
  defaultValues,
  cols,
  fields,
  dropdowns,
  refetchKey,
  onSuccess = () => {},
  onCancel,
  successToastMessage,
}: FormProps) {
  const errorModal = useErrorModal()
  const queryClient = useQueryClient()
  const [error, setError] = useState<any>(null)
  const { control, watch, handleSubmit } = useForm({
    defaultValues,
    resolver: yupResolver(generateYupSchema({ fieldGroups: [fields] })),
  })

  const { data, mutate, isLoading } = useMutation(makePostRequest, {
    onSuccess(data) {
      queryClient.invalidateQueries(refetchKey)
      toast.success(successToastMessage ?? 'Created Successfully')
      onSuccess && onSuccess()
    },
    onError(error: any) {
      setError(error?.response?.data?.message)
      // axiosErrorToast(error)
      errorModal({ error: error })
    },
  })

  const onError = (error) => {
    const errorArray = Object.values(error)?.map((item: any) => item?.message)
    setError(errorArray)
  }

  return (
    <form
      onSubmit={handleSubmit((originalFormData) => {
        const modifiedFormData = onSubmit(originalFormData) ?? originalFormData

        mutate({
          endpoint: endPoint,
          postBody: modifiedFormData,
        })
      }, onError)}
    >
      <RenderForm
        cols={cols}
        fields={fields}
        control={control}
        dropdowns={dropdowns}
      />

      <FormErrorDisplay message={error} />
      <Box
        sx={{
          display: 'flex',
          gap: '20px',
          marginTop: '3rem',
        }}
      >
        <Button
          fullWidth
          type="submit"
          disabled={isLoading}
          endIcon={
            isLoading && <CircularProgress sx={{ color: 'white' }} size={20} />
          }
          {...buttonProps}
        >
          {submitBtn?.label}
        </Button>
        <Button
          fullWidth
          variant="outlined"
          onClick={() => {
            onCancel ? onCancel() : null
          }}
          disabled={isLoading}
          {...buttonProps}
        >
          {cancelBtn?.label}
        </Button>
      </Box>
    </form>
  )
}

export const FormErrorDisplay = ({
  message,
}: {
  message: string | string[]
}) => {
  if (!message) return null

  if (typeof message === 'string')
    return (
      <Alert severity="error" sx={{ marginTop: '1rem' }}>
        {message}
      </Alert>
    )

  return (
    <Alert
      severity="error"
      sx={{
        marginTop: '1rem',
        '& .MuiAlert-icon': {
          display: 'flex',
          alignItems: 'center',
        },
      }}
    >
      <Box>
        {message?.map((item, index) => (
          <Typography color="error" variant="body1" key={index}>
            {item}
          </Typography>
        ))}
      </Box>
    </Alert>
  )
}
