module GraphqlHelpers
  # makes an underscored string look like a fieldname
  # "merge_request" => "mergeRequest"
  def self.fieldnamerize(underscored_field_name)
    graphql_field_name = underscored_field_name.to_s.camelize
    graphql_field_name[0] = graphql_field_name[0].downcase

    graphql_field_name
  end

  # Run a loader's named resolver
  def resolve(resolver_class, obj: nil, args: {}, ctx: {})
    resolver_class.new(object: obj, context: ctx).resolve(args)
  end

  # Runs a block inside a BatchLoader::Executor wrapper
  def batch(max_queries: nil, &blk)
    wrapper = proc do
      begin
        BatchLoader::Executor.ensure_current
        yield
      ensure
        BatchLoader::Executor.clear_current
      end
    end

    if max_queries
      result = nil
      expect { result = wrapper.call }.not_to exceed_query_limit(max_queries)
      result
    else
      wrapper.call
    end
  end

  def graphql_query_for(name, attributes = {}, fields = nil)
    fields ||= all_graphql_fields_for(name.classify)
    attributes = attributes_to_graphql(attributes)
    <<~QUERY
    {
      #{name}(#{attributes}) {
        #{fields}
      }
    }
    QUERY
  end

  def all_graphql_fields_for(class_name)
    type = GitlabSchema.types[class_name.to_s]
    return "" unless type

    type.fields.map do |name, field|
      if scalar?(field)
        name
      else
        "#{name} { #{all_graphql_fields_for(field_type(field))} }"
      end
    end.join("\n")
  end

  def attributes_to_graphql(attributes)
    attributes.map do |name, value|
      "#{GraphqlHelpers.fieldnamerize(name.to_s)}: \"#{value}\""
    end.join(", ")
  end

  def post_graphql(query, current_user: nil)
    post api('/', current_user, version: 'graphql'), query: query
  end

  def graphql_data
    json_response['data']
  end

  def graphql_errors
    json_response['data']
  end

  def scalar?(field)
    field_type(field).kind.scalar?
  end

  def field_type(field)
    if field.type.respond_to?(:of_type)
      field.type.of_type
    else
      field.type
    end
  end
end
