import { router } from '@inertiajs/vue3';
import { useDebounceFn } from '@vueuse/core';
import { ref, watch  } from 'vue';
import type {WatchSource} from 'vue';
import type { DataTableQuery, DataTableSort } from '@/types/data-table';

type UseDataTableQueryOptions = {
    url: string;
    initial: DataTableQuery;
    filterKeys?: string[];
    debounceMs?: number;
};

function buildParams(query: DataTableQuery, filterKeys: string[]): Record<string, string | undefined> {
    const params: Record<string, string | undefined> = {
        search: query.search || undefined,
        sort: query.sort || undefined,
        direction: query.direction || undefined,
    };

    for (const key of filterKeys) {
        params[key] = query[key] || undefined;
    }

    return params;
}

export function useDataTableQuery(options: UseDataTableQueryOptions) {
    const filterKeys = options.filterKeys ?? [];
    const query = ref<DataTableQuery>({ ...options.initial });

    const reload = useDebounceFn(() => {
        router.get(options.url, buildParams(query.value, filterKeys), {
            preserveState: true,
            replace: true,
            preserveScroll: true,
        });
    }, options.debounceMs ?? 300);

    function setSearch(value: string): void {
        query.value.search = value;
        reload();
    }

    function setSort(sort: DataTableSort | null): void {
        query.value.sort = sort?.column;
        query.value.direction = sort?.direction;
        reload();
    }

    function setFilter(key: string, value: string): void {
        query.value[key] = value;
        reload();
    }

    function resetFilters(): void {
        for (const key of filterKeys) {
            query.value[key] = '';
        }

        reload();
    }

    function syncFromServer(filters: DataTableQuery): void {
        query.value = { ...filters };
    }

    return {
        query,
        setSearch,
        setSort,
        setFilter,
        resetFilters,
        reload,
        syncFromServer,
    };
}

export function useDataTableQuerySync(
    filters: WatchSource<DataTableQuery>,
    syncFromServer: (filters: DataTableQuery) => void,
): void {
    watch(filters, (value) => {
        syncFromServer(value);
    });
}
