import { useCallback, useState } from 'react'
import type { FormState } from '../../types/core/form_state'

export interface UseFormOptions<T extends Record<string, unknown>> {
  /** Valores iniciales del formulario */
  initial_values: T
  /** Funcion de validacion sincrona. Retorna errores por campo (undefined = sin error). */
  validate?: (values: T) => Partial<Record<keyof T, string | undefined>>
}

/** Resultado del hook use_form, extiende FormState con metodos de control */
export interface UseFormResult<T extends Record<string, unknown>> extends FormState<T> {
  /** Actualizar un campo individual */
  set_field: <K extends keyof T>(name: K, value: T[K]) => void
  /** Actualizar multiples campos a la vez */
  set_fields: (partial: Partial<T>) => void
  /** Ejecutar validacion manualmente. Retorna true si pasa. */
  validate: () => boolean
  /** Ejecutar validacion y llamar al handler solo si pasa */
  submit: (handler: (values: T) => Promise<void> | void) => Promise<void>
  /** Resetear al estado inicial */
  reset: () => void
}

/**
 * Hook para formularios con validacion sincrona, touched tracking y submit handler.
 * Minimalista: no reemplaza @mantine/form. Para formularios simples sin Mantine.
 */
export function useForm<T extends Record<string, unknown>>(
  opts: UseFormOptions<T>,
): UseFormResult<T> {
  const { initial_values, validate: validateFn } = opts

  const [values, setValues] = useState<T>(initial_values)
  const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({})
  const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({})
  const [isSubmitting, setIsSubmitting] = useState(false)

  const runValidation = useCallback(
    (vals: T): Partial<Record<keyof T, string>> => {
      if (!validateFn) return {}
      const result = validateFn(vals)
      const filtered: Partial<Record<keyof T, string>> = {}
      for (const key in result) {
        const val = result[key as keyof T]
        if (val !== undefined) {
          filtered[key as keyof T] = val
        }
      }
      return filtered
    },
    [validateFn],
  )

  const setField = useCallback(
    <K extends keyof T>(name: K, value: T[K]) => {
      setValues((prev: T) => {
        const next = { ...prev, [name]: value }
        if (validateFn) {
          const newErrors = runValidation(next)
          setErrors(newErrors)
        }
        return next
      })
      setTouched((prev: Partial<Record<keyof T, boolean>>) => ({ ...prev, [name]: true }))
    },
    [validateFn, runValidation],
  )

  const setFields = useCallback(
    (partial: Partial<T>) => {
      setValues((prev: T) => {
        const next = { ...prev, ...partial }
        if (validateFn) {
          const newErrors = runValidation(next)
          setErrors(newErrors)
        }
        return next
      })
      const newTouched: Partial<Record<keyof T, boolean>> = {}
      for (const key in partial) {
        newTouched[key as keyof T] = true
      }
      setTouched((prev: Partial<Record<keyof T, boolean>>) => ({ ...prev, ...newTouched }))
    },
    [validateFn, runValidation],
  )

  const validate = useCallback((): boolean => {
    const newErrors = runValidation(values)
    setErrors(newErrors)
    return Object.keys(newErrors).length === 0
  }, [values, runValidation])

  const submit = useCallback(
    async (handler: (values: T) => Promise<void> | void): Promise<void> => {
      const newErrors = runValidation(values)
      setErrors(newErrors)

      if (Object.keys(newErrors).length > 0) return

      setIsSubmitting(true)
      try {
        await handler(values)
      } finally {
        setIsSubmitting(false)
      }
    },
    [values, runValidation],
  )

  const reset = useCallback(() => {
    setValues(initial_values)
    setErrors({})
    setTouched({})
    setIsSubmitting(false)
  }, [initial_values])

  const isValid = Object.keys(errors).length === 0

  return {
    values,
    errors,
    touched,
    is_valid: isValid,
    is_submitting: isSubmitting,
    set_field: setField,
    set_fields: setFields,
    validate,
    submit,
    reset,
  }
}
