"use client"

import { useState, useMemo, useCallback } from "react"
import { useForm, type DefaultValues, type FieldValues, type UseFormReturn } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { useQueryStates, useQueryState, parseAsInteger } from "nuqs"
import type { ZodType } from "zod"

export type UseFilterParamsOptions<TFormValues extends FieldValues> = {
    schema: ZodType<TFormValues, any, any>
    defaultValues: DefaultValues<TFormValues>
    paramsParsers: Record<string, any>
    mapParamsToFormValues: (params: Record<string, any>) => Partial<TFormValues>
    mapFormValuesToParams: (values: TFormValues) => Record<string, any>
}

export type UseFilterParamsReturn<TFormValues extends FieldValues> = {
    form: UseFormReturn<TFormValues>
    isOpen: boolean
    open: () => void
    close: () => void
    onSubmit: (values: TFormValues) => void
    reset: () => void
    appliedParams: Record<string, unknown>
    activeFilterCount: number
}

export function useFilterParams<TFormValues extends FieldValues>({
    schema,
    defaultValues,
    paramsParsers,
    mapParamsToFormValues,
    mapFormValuesToParams,
}: UseFilterParamsOptions<TFormValues>): UseFilterParamsReturn<TFormValues> {
    const [params, setParams] = useQueryStates(paramsParsers)
    const [, setPage] = useQueryState("page", parseAsInteger)
    const [isOpen, setIsOpen] = useState(false)

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

    const open = useCallback(() => {
        const formValues = mapParamsToFormValues(params)
        form.reset({ ...defaultValues, ...formValues } as any)
        setIsOpen(true)
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [params])

    const close = useCallback(() => {
        setIsOpen(false)
    }, [])

    const onSubmit = useCallback((values: TFormValues) => {
        const mapped = mapFormValuesToParams(values)
        const fullParams: Record<string, any> = {}
        for (const key of Object.keys(paramsParsers)) {
            fullParams[key] = mapped[key] ?? null
        }
        setParams(fullParams)
        setPage(1)
        setIsOpen(false)
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [mapFormValuesToParams, paramsParsers, setParams, setPage])

    const reset = useCallback(() => {
        const nullParams: Record<string, null> = {}
        for (const key of Object.keys(paramsParsers)) {
            nullParams[key] = null
        }
        setParams(nullParams)
        setPage(1)
        form.reset(defaultValues)
        setIsOpen(false)
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [paramsParsers, setParams, setPage])

    const appliedParams = useMemo(() => {
        const result: Record<string, unknown> = {}
        for (const [key, value] of Object.entries(params)) {
            if (value === null || value === undefined || value === "") continue
            if (Array.isArray(value) && value.length === 0) continue
            if (typeof value === "boolean" && value === false) continue
            result[key] = value
        }
        return result
    }, [params])

    const activeFilterCount = Object.keys(appliedParams).length

    return {
        form,
        isOpen,
        open,
        close,
        onSubmit,
        reset,
        appliedParams,
        activeFilterCount,
    }
}
