'use client';

import { useState, useCallback, useMemo } from 'react';
import { useQuery, useQueryClient, type QueryKey } from '@tanstack/react-query';
import { useSearchParams, useRouter, usePathname } from 'next/navigation';

import { apiFetch } from '@/lib/api/client';
import type { PaginatedResponse } from '@/types/api';
import {
  serializeFiltersToParams,
  deserializeFiltersFromParams,
  type FilterDefinition,
  type FilterValues,
} from '@/components/shared/filter-bar';

interface UsePaginatedQueryOptions {
  queryKey: QueryKey;
  endpoint: string;
  initialPage?: number;
  initialPageSize?: number;
  filterDefinitions?: FilterDefinition[];
}

export function usePaginatedQuery<T>({
  queryKey,
  endpoint,
  initialPage = 1,
  initialPageSize = 25,
  filterDefinitions = [],
}: UsePaginatedQueryOptions) {
  const searchParams = useSearchParams();
  const router = useRouter();
  const pathname = usePathname();
  const queryClient = useQueryClient();

  // Read initial state from URL
  const pageFromUrl = Number(searchParams.get('page')) || initialPage;
  const pageSizeFromUrl = Number(searchParams.get('limit')) || initialPageSize;
  const sortFieldFromUrl = searchParams.get('sort') ?? undefined;
  const sortOrderFromUrl = (searchParams.get('order') as 'asc' | 'desc') ?? 'desc';

  const [page, setPageState] = useState(pageFromUrl);
  const [pageSize, setPageSizeState] = useState(pageSizeFromUrl);
  const [sort, setSortState] = useState<{ field: string; direction: 'asc' | 'desc' } | undefined>(
    sortFieldFromUrl ? { field: sortFieldFromUrl, direction: sortOrderFromUrl } : undefined,
  );
  const [filters, setFiltersState] = useState<FilterValues>(() =>
    deserializeFiltersFromParams(searchParams, filterDefinitions),
  );

  // Sync state to URL
  const syncUrl = useCallback(
    (p: number, ps: number, s?: typeof sort, f?: FilterValues) => {
      const params = new URLSearchParams();
      if (p !== 1) params.set('page', String(p));
      if (ps !== initialPageSize) params.set('limit', String(ps));
      if (s) {
        params.set('sort', s.field);
        params.set('order', s.direction);
      }
      if (f) {
        const filterParams = serializeFiltersToParams(f);
        filterParams.forEach((value, key) => params.set(key, value));
      }
      // Keep existing tab param
      const tab = searchParams.get('tab');
      if (tab) params.set('tab', tab);

      const qs = params.toString();
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      router.replace(`${pathname}${qs ? `?${qs}` : ''}` as any, { scroll: false });
    },
    [pathname, router, searchParams, initialPageSize],
  );

  function setPage(p: number) {
    setPageState(p);
    syncUrl(p, pageSize, sort, filters);
  }

  function setPageSize(ps: number) {
    setPageSizeState(ps);
    setPageState(1);
    syncUrl(1, ps, sort, filters);
  }

  function setSort(field: string, direction: 'asc' | 'desc') {
    const newSort = { field, direction };
    setSortState(newSort);
    setPageState(1);
    syncUrl(1, pageSize, newSort, filters);
  }

  function setFilter(key: string, value: unknown) {
    const newFilters = { ...filters };
    if (value === undefined || value === null) {
      delete newFilters[key];
    } else {
      newFilters[key] = value;
    }
    setFiltersState(newFilters);
    setPageState(1);
    syncUrl(1, pageSize, sort, newFilters);
  }

  function clearFilters() {
    setFiltersState({});
    setPageState(1);
    syncUrl(1, pageSize, sort, {});
  }

  // Build query string for API
  const apiParams = useMemo(() => {
    const params = new URLSearchParams();
    params.set('page', String(page));
    params.set('limit', String(pageSize));
    if (sort) {
      params.set('sort', sort.field);
      params.set('order', sort.direction);
    }
    const filterParams = serializeFiltersToParams(filters);
    filterParams.forEach((value, key) => params.set(key, value));
    return params.toString();
  }, [page, pageSize, sort, filters]);

  const fullQueryKey = [...queryKey, apiParams];

  const { data, isLoading, isFetching } = useQuery<PaginatedResponse<T>>({
    queryKey: fullQueryKey,
    queryFn: () =>
      apiFetch<PaginatedResponse<T>>(`${endpoint}?${apiParams}`),
  });

  const pagination = data?.pagination
    ? {
        page: data.pagination.page,
        pageSize: data.pagination.pageSize,
        total: data.pagination.total,
        totalPages: data.pagination.totalPages,
      }
    : { page, pageSize, total: 0, totalPages: 0 };

  /**
   * Optimistically removes an item from the cached list (e.g., after archive).
   */
  function optimisticRemove(id: string) {
    queryClient.setQueryData<PaginatedResponse<T>>(fullQueryKey, (old) => {
      if (!old) return old;
      return {
        ...old,
        data: old.data.filter((item) => (item as Record<string, unknown>).id !== id),
        pagination: {
          ...old.pagination,
          total: old.pagination.total - 1,
        },
      };
    });
  }

  return {
    data: data?.data ?? [],
    pagination,
    isLoading,
    isFetching,
    sort,
    setSort,
    page,
    setPage,
    pageSize,
    setPageSize,
    filters,
    setFilter,
    clearFilters,
    optimisticRemove,
  };
}
