import { ref } from 'vue'

export default function useYup(validationSchema, getValues) {
  const errors = ref({})

  const readFormValues = () => {
    if (typeof getValues !== 'function') return {}
    const v = getValues()
    return v && typeof v === 'object' ? v : {}
  }

  const validate = async (values, options) => {
    const mergeOptions = { abortEarly: false, stripUnknown: true, ...options }
    try {
      const response = await validationSchema.validate(values, mergeOptions)
      if (!(response instanceof Error)) {
        errors.value = {}
        return { isValid: true, payload: response }
      }
      return { isValid: false, payload: response }
    } catch (error) {
      if (error.inner) {
        const newErrors = {}
        error.inner.forEach((validationError) => {
          newErrors[validationError.path] = validationError.message
        })
        errors.value = newErrors
        return { isValid: false }
      }
      return { isValid: false, payload: error }
    }
  }

  const validateAt = async (field, value) => {
    try {
      const pathParts = field.split('.')
      const lastPart = pathParts.pop()
      let schemaContext = validationSchema
      let context = { ...readFormValues() }
      if (pathParts.length > 0) {
        pathParts.forEach((part) => {
          if (part.includes('[')) {
            const [arrayPart, indexPart] = part.split(/[[\]]/).filter(Boolean)
            schemaContext = schemaContext.fields[arrayPart].innerType
            context = { ...context, [arrayPart]: (context[arrayPart] || [])[indexPart] || {} }
          } else {
            context[part] = context[part] || {}
            schemaContext = schemaContext.fields[part]
          }
        })

        context[lastPart] = value
        await schemaContext.validateAt(lastPart, context)
        errors.value[field] = null
      } else {
        await validationSchema.validateAt(field, { ...context, [field]: value })
        errors.value[field] = null
      }
    } catch (error) {
      errors.value[field] = error.message
    }
  }

  const resetErrors = () => {
    errors.value = {}
  }

  const setError = (field, error) => {
    errors.value[field] = error
  }

  return {
    validate,
    validateAt,
    errors,
    resetErrors,
    setError,
  }
}
