# frozen_string_literal: true

module Gitlab
  module Pagination
    module Keyset
      class Pager < Gitlab::Pagination::Base
        attr_reader :request

        def initialize(request)
          @request = request
        end

        def paginate(relation)
          # Validate assumption: The last two columns must match the page order_by
          validate_order!(relation)

          relation.limit(page.per_page) # rubocop: disable CodeReuse/ActiveRecord
        end

        def finalize(records)
          apply_headers(records.last)
        end

        private

        def apply_headers(last_record_in_page)
          return unless last_record_in_page

          lower_bounds = last_record_in_page&.slice(page.order_by.keys)
          next_page = page.next(lower_bounds)

          request.apply_headers(next_page)
        end

        def page
          @page ||= request.page
        end

        def validate_order!(rel)
          present_order = rel.order_values.map { |val| [val.expr.name.to_sym, val.direction] }.last(2).to_h

          unless page.order_by == present_order
            raise ArgumentError, "Page's order_by does not match the relation's order: #{present_order} vs #{page.order_by}"
          end
        end
      end
    end
  end
end
