"use client"

import { useEffect } from "react"
import { useForm, type DefaultValues, type FieldValues, type UseFormReturn } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { useQuery, useQueryClient, type QueryKey } from "@tanstack/react-query"
import type { ZodType } from "zod"

type UseResourceFormOptions<TFormValues extends FieldValues, TApiData = unknown> = {
    schema: ZodType<TFormValues, any, any>
    defaultValues: DefaultValues<TFormValues>
    resourceId?: string | null
    initialize?: (id: string) => Promise<TApiData>
    mapToFormValues: (data: TApiData) => TFormValues
    initialData?: TApiData | null
    queryKey?: QueryKey
}

type UseResourceFormReturn<TFormValues extends FieldValues, TApiData = unknown> = {
    form: UseFormReturn<TFormValues>
    isEditing: boolean
    isInitializing: boolean
    invalidate: () => void
    data: TApiData | undefined
}

export function useResourceForm<TFormValues extends FieldValues, TApiData = unknown>({
    schema,
    defaultValues,
    resourceId,
    initialize,
    mapToFormValues,
    initialData,
    queryKey,
}: UseResourceFormOptions<TFormValues, TApiData>): UseResourceFormReturn<TFormValues, TApiData> {
    const isEditing = !!resourceId
    const queryClient = useQueryClient()
    const resolvedQueryKey = queryKey ?? ["resource", resourceId]

    const { data: queriedData, isLoading: isQueryLoading } = useQuery<TApiData>({
        queryKey: resolvedQueryKey,
        queryFn: () => initialize!(resourceId!),
        enabled: isEditing && !!initialize,
        staleTime: 0,
        refetchOnMount: "always",
    })

    const resolvedData: TApiData | undefined =
        queriedData ?? (isEditing ? (initialData ?? undefined) : undefined)

    const form = useForm<TFormValues>({
        resolver: zodResolver(schema) as any,
        defaultValues,
    })

    useEffect(() => {
        if (!isEditing) {
            if (initialData) {
                form.reset({ ...defaultValues, ...mapToFormValues(initialData) } as any)
            } else {
                form.reset(defaultValues)
            }
            return
        }

        if (resolvedData) {
            form.reset(mapToFormValues(resolvedData) as any)
        }
    }, [isEditing, resolvedData, initialData]) // eslint-disable-line react-hooks/exhaustive-deps

    const invalidate = () => {
        queryClient.invalidateQueries({ queryKey: resolvedQueryKey })
    }

    return {
        form,
        isEditing,
        isInitializing: isEditing && !!initialize && isQueryLoading,
        invalidate,
        data: resolvedData,
    }
}
