import { router } from '@inertiajs/react';
import { useCallback, useState } from 'react';
import type { PaginationState } from '@/components/data-table';

type UseServerTableOptions = {
    route: () => string;
    pagination: PaginationState;
    filters?: Record<string, string | undefined>;
    filterWithParams?: boolean;
    /**
     * Prop keys to pass as Inertia's `reset` visit option whenever search or
     * filters change, so mergeable props (e.g. `Inertia::scroll()` used for
     * infinite scroll) are replaced instead of appended to.
     */
    resetKeys?: string[];
};

export function useServerTable({
    route,
    pagination,
    filters,
    filterWithParams = true,
    resetKeys,
}: UseServerTableOptions) {
    const [search, setSearch] = useState(
        () => new URLSearchParams(window.location.search).get('search') ?? '',
    );
    const [filterOpen, setFilterOpen] = useState(false);

    const handlePageChange = useCallback(
        (page: number) => {
            router.get(
                route(),
                {
                    ...filters,
                    page,
                    per_page: pagination.per_page,
                    search,
                },
                { preserveState: true, replace: true },
            );
        },
        [route, filters, pagination.per_page, search],
    );

    const handlePerPageChange = useCallback(
        (perPage: number) => {
            router.get(
                route(),
                {
                    ...filters,
                    page: 1,
                    per_page: perPage,
                    search,
                },
                { preserveState: true, replace: true },
            );
        },
        [route, filters, search],
    );

    const handleSearchChange = useCallback(
        (value: string) => {
            setSearch(value);
            router.get(
                route(),
                {
                    ...filters,
                    page: 1,
                    per_page: pagination.per_page,
                    search: value,
                },
                {
                    preserveState: true,
                    replace: true,
                    ...(resetKeys ? { reset: resetKeys } : {}),
                },
            );
        },
        [route, filters, pagination.per_page, resetKeys],
    );

    function applyFilter(key: string, value: string) {
        const newFilters = { ...filters };

        if (value === '' || value === 'all') {
            delete newFilters[key];
        } else {
            newFilters[key] = value;
        }

        router.get(
            route(),
            filterWithParams
                ? {
                      ...newFilters,
                      page: 1,
                      per_page: pagination.per_page,
                      search,
                  }
                : newFilters,
            {
                preserveState: true,
                replace: true,
                ...(resetKeys ? { reset: resetKeys } : {}),
            },
        );
    }

    function applyFilters(newFilters: Record<string, string | undefined>) {
        router.get(
            route(),
            filterWithParams
                ? {
                      ...newFilters,
                      page: 1,
                      per_page: pagination.per_page,
                      search,
                  }
                : newFilters,
            {
                preserveState: true,
                replace: true,
                ...(resetKeys ? { reset: resetKeys } : {}),
            },
        );
    }

    function clearFilters() {
        router.get(
            route(),
            filterWithParams
                ? {
                      page: 1,
                      per_page: pagination.per_page,
                      search,
                  }
                : {},
            {
                preserveState: true,
                replace: true,
                ...(resetKeys ? { reset: resetKeys } : {}),
            },
        );
        setFilterOpen(false);
    }

    return {
        search,
        filterOpen,
        setFilterOpen,
        handlePageChange,
        handlePerPageChange,
        handleSearchChange,
        applyFilter,
        applyFilters,
        clearFilters,
    };
}
