lib/api/paging/rest_paginator_builder.rb
# frozen_string_literal: true

module Api
  module Paging
    class RestPaginatorBuilder
      MAX_LIMIT = 100
      DEFAULT_LIMIT = 15

      def initialize(base_query, request, allow_default_page=true, default_limit=DEFAULT_LIMIT)
        @base_query = base_query
        @request = request
        @allow_default_page = allow_default_page
        @default_limit = if default_limit < MAX_LIMIT && default_limit > 0
                           default_limit
                         else
                           DEFAULT_LIMIT
                         end
      end

      def index_pager(params)
        current_page = current_page_settings(params)
        paged_response_builder(IndexPaginator.new(@base_query, current_page, limit_settings(params)))
      end

      def time_pager(params, query_time_field="created_at", data_time_field=query_time_field)
        is_descending, current_time = time_settings(params)
        paged_response_builder(
          TimePaginator.new(
            query_base:       @base_query,
            query_time_field: query_time_field,
            data_time_field:  data_time_field,
            current_time:     current_time,
            is_descending:    is_descending,
            limit:            limit_settings(params)
          )
        )
      end

      private

      def current_page_settings(params)
        if params["page"]
          requested_page = params["page"].to_i
          requested_page = 1 if requested_page < 1
          requested_page
        elsif @allow_default_page
          1
        else
          raise ActionController::ParameterMissing
        end
      end

      def paged_response_builder(paginator)
        Api::Paging::RestPagedResponseBuilder.new(paginator, @request)
      end

      def time_settings(params)
        time_params = params.permit("before", "after")
        time_params["before"] = (Time.current + 1.year).iso8601 if time_params.empty? && @allow_default_page

        raise "Missing time parameters for query building" if time_params.empty?

        if time_params["before"]
          is_descending = true
          current_time = Time.iso8601(time_params["before"])
        else
          is_descending = false
          current_time = Time.iso8601(time_params["after"])
        end
        [is_descending, current_time]
      end

      def limit_settings(params)
        requested_limit = params["per_page"].to_i if params["per_page"]
        return @default_limit unless requested_limit

        requested_limit = [1, requested_limit].max
        [requested_limit, MAX_LIMIT].min
      end
    end
  end
end
