import '../models/paginated_result.dart';

/// 페이지네이션 API에서 모든 항목을 수집하는 도우미.
///
/// - 백엔드가 기본적으로 페이지 크기 제한을 두는 경우, 반복 호출로 전체 목록을 확보한다.
/// - `maxPages`는 안전장치로 사용하며, 비정상 응답으로 무한 루프에 빠지는 것을 막는다.
typedef PaginatedRequest<T> =
    Future<PaginatedResult<T>> Function(int page, int pageSize);

/// 페이지 단위로 제공되는 데이터를 모두 불러온다.
///
/// - [request]는 페이지 번호와 페이지 크기를 받아 `PaginatedResult`를 반환해야 한다.
/// - [pageSize]는 첫 호출에 사용할 기본 페이지 크기이며, 서버가 다른 값을 돌려주면
///   이후 호출에서는 응답 값을 따른다.
/// - [maxPages]는 허용할 최대 페이지 수로, 비정상 응답을 대비한 제한값이다.
Future<List<T>> fetchAllPaginatedItems<T>({
  required PaginatedRequest<T> request,
  int pageSize = 100,
  int maxPages = 50,
}) async {
  final results = <T>[];
  var currentPage = 1;
  var pagesFetched = 0;
  var effectivePageSize = pageSize > 0 ? pageSize : 100;

  while (pagesFetched < maxPages) {
    final previousLength = results.length;
    final response = await request(currentPage, effectivePageSize);
    pagesFetched += 1;

    final items = response.items;
    if (items.isEmpty) {
      break;
    }

    results.addAll(items);
    final added = results.length - previousLength;

    if (added <= 0) {
      // 새 항목을 받지 못했다면 더 이상 진행하지 않는다.
      break;
    }

    final receivedPageSize = () {
      if (response.pageSize > 0) {
        return response.pageSize;
      }
      if (items.isNotEmpty) {
        return items.length;
      }
      return effectivePageSize;
    }();

    if (items.length < receivedPageSize) {
      // 마지막 페이지에 도달한 경우 즉시 종료한다.
      break;
    }

    effectivePageSize = receivedPageSize;
    final nextPage = response.page > 0 ? response.page + 1 : currentPage + 1;
    currentPage = nextPage > currentPage ? nextPage : currentPage + 1;
  }

  return results;
}
