class Paginator
  WINDOW_SIZE = 11

  attr_accessor :objs, :params_page, :context, :url_params

  def initialize(objs, options = {})
    self.objs = objs
    self.params_page = options[:page]
    self.context = options[:context]
    self.url_params = options[:url_params]
  end

  def left_page
    [1, current_page - WINDOW_SIZE / 2].max
  end

  def right_page
    [total_pages, left_page + WINDOW_SIZE - 1].min
  end

  def left_padding?
    left_page > 1
  end

  def right_padding?
    right_page < total_pages
  end

  def pages_to_display
    left_page..right_page
  end

  def pages?
    objs.present? && total_pages > 1
  end

  def previous_page
    current_page - 1
  end

  def next_page
    current_page + 1
  end

  def klass
    objs.first.class
  end

  def additional_url_params
    url_params.presence || {}
  end

  def url(page)
    params = context.params.permit!.merge(page: page).merge(additional_url_params)
    context.url_for(params)
  end

  def next_page_url
    url(next_page)
  end

  def previous_page_url
    url(previous_page)
  end

  def first_page_url
    url(1)
  end

  def last_page_url
    url(total_pages)
  end

  def current?(page)
    current_page == page
  end

  def current_page
    (params_page.presence || 1).to_i
  end

  def first_page?
    current_page == 1
  end

  def per_page
    (objs.per_page.presence || objs.length).to_i
  end

  def invalid_class_error
    "Cannot paginate #{objs.class}. Paginator expects #{PaginatedArray}. \
    Be sure to return `paginate objects` in your service"
  end

  def total_pages
    raise invalid_class_error unless objs.respond_to?(:total_pages)

    return objs.total_pages.to_i if objs.total_pages
    return 1 unless objs.total_count
    return (objs.total_count.to_f / per_page.to_f).ceil
  end

  def last_page?
    current_page == total_pages
  end
end
