import type * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'

/**
 * Form handling composable for consistent form state management
 * Works with Nuxt UI's UForm component and Zod schemas
 *
 * @param schema - Zod schema for validation
 * @param initialData - Initial form data (optional)
 * @returns Form state and methods
 *
 * @example
 * const schema = z.object({
 *   name: z.string().min(1),
 *   email: z.string().email()
 * })
 *
 * const form = useForm(schema, { name: '', email: '' })
 *
 * // In template:
 * // <UForm :schema="schema" :state="form.state" @submit="form.handleSubmit(onSubmit)">
 */
export function useForm<T extends z.ZodType>(
  schema: T,
  initialData?: Partial<z.infer<T>>
) {
  type FormData = z.infer<T>

  // Form state
  const state = reactive<Partial<FormData>>(initialData || {})
  const errors = ref<Record<string, string>>({})
  const isSubmitting = ref(false)
  const isDirty = ref(false)
  const isValid = ref(false)

  /**
   * Validate the form data
   * @returns true if valid, false otherwise
   */
  const validate = (): boolean => {
    const result = schema.safeParse(state)

    if (!result.success) {
      // Flatten errors to a simple object
      const fieldErrors: Record<string, string> = {}
      result.error.issues.forEach((issue) => {
        const path = issue.path.join('.')
        fieldErrors[path] = issue.message
      })
      errors.value = fieldErrors
      isValid.value = false
      return false
    }

    errors.value = {}
    isValid.value = true
    return true
  }

  /**
   * Reset form to initial state
   */
  const reset = () => {
    const keys = Object.keys(state) as Array<keyof FormData>
    keys.forEach((key) => {
      // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
      delete (state as Record<string, unknown>)[key as string]
    })
    if (initialData) {
      Object.assign(state, initialData)
    }
    errors.value = {}
    isSubmitting.value = false
    isDirty.value = false
    isValid.value = false
  }

  /**
   * Set form field value
   */
  const setField = <K extends keyof FormData>(field: K, value: FormData[K]) => {
    (state as Record<string, unknown>)[field as string] = value
    isDirty.value = true
    // Clear error for this field when user starts typing
    const fieldKey = String(field)
    if (errors.value[fieldKey]) {
      // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
      delete errors.value[fieldKey]
    }
  }

  /**
   * Set multiple form fields at once
   */
  const setFields = (values: Partial<FormData>) => {
    Object.assign(state, values)
    isDirty.value = true
  }

  /**
   * Get error message for a field
   */
  const getFieldError = (field: string): string | undefined => {
    return errors.value[field]
  }

  /**
   * Check if a field has an error
   */
  const hasFieldError = (field: string): boolean => {
    return !!errors.value[field]
  }

  /**
   * Handle form submission
   * Validates form and calls handler if valid
   *
   * @param handler - Async function to handle form submission
   * @param options - Submission options
   */
  const handleSubmit = async (
    handler: (data: FormData) => Promise<unknown>,
    options?: {
      onSuccess?: () => void
      onError?: (error: unknown) => void
      resetOnSuccess?: boolean
    }
  ) => {
    // Validate before submitting
    if (!validate()) {
      return
    }

    isSubmitting.value = true
    try {
      const validatedData = schema.parse(state) as FormData
      await handler(validatedData)

      options?.onSuccess?.()

      if (options?.resetOnSuccess !== false) {
        reset()
      }
    } catch (error) {
      // Handle validation errors from API
      if (error && typeof error === 'object' && 'data' in error) {
        const errorData = error as { data?: { details?: Record<string, string> } }
        if (errorData.data?.details) {
          errors.value = errorData.data.details as Record<string, string>
        }
      }

      options?.onError?.(error)
      throw error
    } finally {
      isSubmitting.value = false
    }
  }

  /**
   * Handle Nuxt UI FormSubmitEvent
   * Convenience wrapper for UForm's @submit event
   */
  const handleFormSubmit = async (
    event: FormSubmitEvent<FormData>,
    handler: (data: FormData) => Promise<unknown>,
    options?: {
      onSuccess?: () => void
      onError?: (error: unknown) => void
      resetOnSuccess?: boolean
    }
  ) => {
    // Update state with event data
    Object.assign(state, event.data)
    return handleSubmit(handler, options)
  }

  // Watch for changes to mark form as dirty
  watch(state, () => {
    isDirty.value = true
  }, { deep: true })

  // Validate on change (debounced)
  let validationTimeout: ReturnType<typeof setTimeout> | null = null
  watch(state, () => {
    if (validationTimeout) {
      clearTimeout(validationTimeout)
    }
    validationTimeout = setTimeout(() => {
      validate()
    }, 300)
  }, { deep: true })

  return {
    // State
    state,
    errors,
    isSubmitting,
    isDirty,
    isValid,

    // Methods
    validate,
    reset,
    setField,
    setFields,
    getFieldError,
    hasFieldError,
    handleSubmit,
    handleFormSubmit
  }
}
