import { useState, useCallback } from 'react'

import {
  useQuery,
  type UseQueryOptions,
  type QueryKey,
} from '@tanstack/react-query'

/**
 * Paginated response structure
 */
export interface PaginatedResponse<T> {
  data: T[];
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;
}

/**
 * Pagination parameters
 */
export interface PaginationParams {
  page: number;
  pageSize: number;
  sortBy?: string;
  sortOrder?: 'asc' | 'desc';
  filters?: Record<string, unknown>;
}

/**
 * Options for usePaginatedQuery
 */
export interface UsePaginatedQueryOptions<T> {
  /**
   * Base query key
   */
  queryKey: QueryKey;

  /**
   * Function to fetch paginated data
   */
  queryFn: (params: PaginationParams) => Promise<PaginatedResponse<T>>;

  /**
   * Initial page number
   * @default 1
   */
  initialPage?: number;

  /**
   * Initial page size
   * @default 10
   */
  initialPageSize?: number;

  /**
   * Initial sort field
   */
  initialSortBy?: string;

  /**
   * Initial sort order
   * @default 'asc'
   */
  initialSortOrder?: 'asc' | 'desc';

  /**
   * Initial filters
   */
  initialFilters?: Record<string, unknown>;

  /**
   * Additional query options
   */
  queryOptions?: Omit<UseQueryOptions<PaginatedResponse<T>>, 'queryKey' | 'queryFn'>;
}

/**
 * Return type for usePaginatedQuery
 */
export interface UsePaginatedQueryResult<T> {
  // Data
  data: T[];
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;

  // Query state
  isLoading: boolean;
  isError: boolean;
  error: Error | null;
  isFetching: boolean;

  // Pagination controls
  nextPage: () => void;
  previousPage: () => void;
  goToPage: (page: number) => void;
  setPageSize: (size: number) => void;
  canNextPage: boolean;
  canPreviousPage: boolean;

  // Sorting
  sortBy: string | undefined;
  sortOrder: 'asc' | 'desc';
  setSorting: (field: string, order?: 'asc' | 'desc') => void;

  // Filtering
  filters: Record<string, unknown>;
  setFilters: (filters: Record<string, unknown>) => void;
  setFilter: (key: string, value: unknown) => void;
  clearFilters: () => void;

  // Refetch
  refetch: () => void;
}

/**
 * Hook for paginated queries with built-in pagination controls
 *
 * Provides pagination state management, sorting, filtering, and
 * automatic query key management.
 *
 * @example
 * ```typescript
 * function UserList() {
 *   const {
 *     data: users,
 *     isLoading,
 *     page,
 *     totalPages,
 *     nextPage,
 *     previousPage,
 *     setSorting,
 *     setFilters,
 *   } = usePaginatedQuery({
 *     queryKey: ['users'],
 *     queryFn: ({ page, pageSize, sortBy, sortOrder, filters }) =>
 *       apiClient.get('/users', {
 *         params: { page, pageSize, sortBy, sortOrder, ...filters },
 *       }),
 *     initialPageSize: 20,
 *     initialSortBy: 'createdAt',
 *     initialSortOrder: 'desc',
 *   });
 *
 *   return (
 *     <div>
 *       {users.map(user => <UserCard key={user.id} user={user} />)}
 *       <Pagination
 *         page={page}
 *         totalPages={totalPages}
 *         onNext={nextPage}
 *         onPrevious={previousPage}
 *       />
 *     </div>
 *   );
 * }
 * ```
 */
export function usePaginatedQuery<T>(
  options: UsePaginatedQueryOptions<T>
): UsePaginatedQueryResult<T> {
  const {
    queryKey,
    queryFn,
    initialPage = 1,
    initialPageSize = 10,
    initialSortBy,
    initialSortOrder = 'asc',
    initialFilters = {},
    queryOptions,
  } = options

  // Pagination state
  const [page, setPage] = useState(initialPage)
  const [pageSize, setPageSize] = useState(initialPageSize)

  // Sorting state
  const [sortBy, setSortBy] = useState(initialSortBy)
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>(initialSortOrder)

  // Filtering state
  const [filters, setFilters] = useState(initialFilters)

  // Query
  const query = useQuery<PaginatedResponse<T>>({
    queryKey: [...queryKey, { page, pageSize, sortBy, sortOrder, filters }],
    queryFn: () => queryFn({ page, pageSize, sortBy, sortOrder, filters }),
    ...queryOptions,
  })

  // Pagination controls
  const nextPage = useCallback(() => {
    if (query.data && page < query.data.totalPages) {
      setPage((prev) => prev + 1)
    }
  }, [page, query.data])

  const previousPage = useCallback(() => {
    if (page > 1) {
      setPage((prev) => prev - 1)
    }
  }, [page])

  const goToPage = useCallback((newPage: number) => {
    if (newPage >= 1 && query.data && newPage <= query.data.totalPages) {
      setPage(newPage)
    }
  }, [query.data])

  const handleSetPageSize = useCallback((size: number) => {
    setPageSize(size)
    setPage(1) // Reset to first page when changing page size
  }, [])

  // Sorting controls
  const setSorting = useCallback((field: string, order: 'asc' | 'desc' = 'asc') => {
    setSortBy(field)
    setSortOrder(order)
    setPage(1) // Reset to first page when sorting changes
  }, [])

  // Filtering controls
  const handleSetFilters = useCallback((newFilters: Record<string, unknown>) => {
    setFilters(newFilters)
    setPage(1) // Reset to first page when filters change
  }, [])

  const setFilter = useCallback((key: string, value: unknown) => {
    setFilters((prev) => ({ ...prev, [key]: value }))
    setPage(1)
  }, [])

  const clearFilters = useCallback(() => {
    setFilters({})
    setPage(1)
  }, [])

  return {
    // Data
    data: query.data?.data ?? [],
    total: query.data?.total ?? 0,
    page: query.data?.page ?? page,
    pageSize: query.data?.pageSize ?? pageSize,
    totalPages: query.data?.totalPages ?? 0,

    // Query state
    isLoading: query.isLoading,
    isError: query.isError,
    error: query.error,
    isFetching: query.isFetching,

    // Pagination controls
    nextPage,
    previousPage,
    goToPage,
    setPageSize: handleSetPageSize,
    canNextPage: !!query.data && page < query.data.totalPages,
    canPreviousPage: page > 1,

    // Sorting
    sortBy,
    sortOrder,
    setSorting,

    // Filtering
    filters,
    setFilters: handleSetFilters,
    setFilter,
    clearFilters,

    // Refetch
    refetch: query.refetch,
  }
}
