import { useCallback, useEffect, useMemo, useState } from "react";
import { toPageQuery } from "@/shared/api/query";
import { useAdminQuery } from "./useAdminQuery.js";

const defaultPageSize = 50;
const emptyPage = { items: [], total: 0, page: 1, pageSize: defaultPageSize };

export function usePaginatedQuery({ errorMessage, fetcher, filters = {}, page, pageSize = defaultPageSize, queryKey }) {
  const requestQuery = useMemo(
    () => toPageQuery({ ...filters, page, pageSize }),
    [filters, page, pageSize]
  );
  const resetKey = useMemo(() => JSON.stringify({ filters, pageSize }), [filters, pageSize]);
  const queryFn = useCallback(() => fetcher(requestQuery), [fetcher, requestQuery]);
  const [mergedData, setMergedData] = useState(emptyPage);

  const query = useAdminQuery(queryFn, {
    errorMessage,
    initialData: emptyPage,
    keepPreviousData: true,
    queryKey: queryKey || ["paginated", requestQuery]
  });

  useEffect(() => {
    setMergedData({ ...emptyPage, pageSize });
  }, [pageSize, resetKey]);

  useEffect(() => {
    const nextData = query.data || emptyPage;
    const nextItems = Array.isArray(nextData.items) ? nextData.items : [];
    const nextPage = Number(nextData.page || page || 1);
    const nextPageSize = Number(nextData.pageSize || pageSize || defaultPageSize);
    const nextTotal = Number(nextData.total || 0);

    setMergedData((current) => {
      if (nextPage <= 1) {
        return { ...nextData, items: nextItems, page: nextPage, pageSize: nextPageSize, total: nextTotal };
      }

      const mergedItems = mergePaginatedItems(current.items || [], nextItems);
      return {
        ...nextData,
        items: mergedItems,
        page: nextPage,
        pageSize: nextPageSize,
        total: nextTotal
      };
    });
  }, [page, pageSize, query.data]);

  return {
    ...query,
    data: mergedData,
    loading: query.loading && (mergedData.items || []).length === 0,
    loadingMore: query.loading && (mergedData.items || []).length > 0
  };
}

export function mergePaginatedItems(currentItems, nextItems) {
  const seen = new Set();
  return [...currentItems, ...nextItems].filter((item, index) => {
    const key = itemKey(item, index);
    if (seen.has(key)) {
      return false;
    }
    seen.add(key);
    return true;
  });
}

function itemKey(item, index) {
  if (!item || typeof item !== "object") {
    return `value:${String(item)}:${index}`;
  }
  for (const key of paginatedIdentityKeys) {
    const value = item[key];
    if (value !== undefined && value !== null && value !== "") {
      return `${key}:${String(value)}`;
    }
  }
  return `index:${index}`;
}

const paginatedIdentityKeys = [
  "id",
  "entryId",
  "transactionId",
  "billId",
  "orderId",
  "recordId",
  "logId",
  "settlementId",
  "claimId",
  "grantId",
  "reportId",
  "roleId",
  "permissionId",
  "groupId",
  "resourceId",
  "productId",
  "roomId",
  "giftId",
  "taskId",
  "userId",
  "key"
];
