require 'httparty'
require 'addressable'

class GitlabApi
  ENDPOINT = 'https://gitlab.com/api/v4'

  UpdateFailed = Class.new(StandardError)

  def initialize(token: nil)
    @token = token
  end

  def count(path)
    get(path).headers['X-Total']
  end

  def get(path)
    path = "#{ENDPOINT}/#{path}" unless path.start_with?(ENDPOINT)

    options = { headers: { 'Private-Token': token } }

    url = Addressable::URI.parse(path)
    existing_query_values = url.query_values || {}
    existing_query_values['per_page'] ||= 50
    url.query_values = existing_query_values

    HTTParty.get(url.to_s, options).tap do |response|
      check_response_code!(:get, url, response)
    end
  end

  def post(path, body:)
    post_or_put(path, body: body, method: :post)
  end

  def put(path, body:)
    post_or_put(path, body: body, method: :put)
  end

  private

  attr_reader :token

  def post_or_put(path, body:, method:)
    path = "#{ENDPOINT}/#{path}" unless path.start_with?(ENDPOINT)

    options = {
      body: body,
      headers: { 'Private-Token': token }
    }

    HTTParty.send(method, path, options).tap do |response|
      expected_code = method == :post ? 201 : 200

      check_response_code!(method, path, response, expected_code: expected_code)
    end
  end

  def check_response_code!(method, path, response, expected_code: 200)
    return if response.code == expected_code

    puts "#{method.to_s.upcase} to #{path} failed!"
    puts ''
    puts "Response code: #{response.code}. Body:"
    puts response.body

    raise UpdateFailed
  end
end
