module ExpectationHelpers
  def expect_attributes attrs
    expect_json 'data.attributes', dasherize_keys(attrs)
  end

  def expect_attributes_in_list attrs
    expect(json_body[:data]).to_not be_empty
    expect_json 'data.?.attributes', dasherize_keys(attrs)
  end

  def expect_relationship attrs, in_list = false
    # If looking for item in a list, need to change location string
    location = if in_list
                 "data.?.relationships.#{attrs[:key]}"
               else
                 "data.relationships.#{attrs[:key]}"
               end

    expect_json "#{location}.links.related", attrs[:link] if attrs[:link]

    if attrs[:id]
      location = "#{location}.data"
      type = attrs[:type] || attrs[:key].pluralize
      id_value = attrs[:id]
      if id_value.respond_to? :each
        # if an array if ids were passed in, look for each of them in the list
        location = "#{location}.?"
        id_value.each do |id|
          # TODO: also look for included thing?
          expect_json location, type: type, id: id
        end
      else
        # otherwise just look for it
        # TODO: also look for included thing?
        expect_json location, type: type, id: id_value
      end
    end
  end

  def expect_relationship_in_list attrs
    expect(json_body[:data]).to_not be_empty
    expect_relationship attrs, in_list: true
  end

  def expect_item_to_not_be_in_list dont_find_me, opts = {}
    opts[:type] ||= jsonapi_type dont_find_me
    expect(json_body[:data]).to_not be_empty
    json_body[:data].each do |item|
      expect(jsonapi_match?(dont_find_me, item, opts[:type])).to be_falsey
    end
  end

  def expect_item_in_list find_me, opts = {}
    opts[:type] ||= jsonapi_type find_me
    expect(json_body[:data]).to_not be_empty
    found = json_body[:data].detect do |item|
      jsonapi_match? find_me, item, opts[:type]
    end
    expect(found).to be_truthy
  end

  def expect_item_count number
    expect_json_sizes data: number
  end

  private

  def dasherize_keys hash
    hash.deep_transform_keys { |key| key.to_s.dasherize.to_sym }
  end

  def jsonapi_match? model, data, type
    (data[:type] == type) && (data[:id] == model.id.to_s)
  end

  def jsonapi_type model
    model.class.to_s.underscore.downcase.pluralize.dasherize
  end
end

RSpec.configure do |config|
  config.include ExpectationHelpers
end