# frozen_string_literal: true

return if Rails.env.production?

module Gitlab
  module Graphql
    module Docs
      # Helper with functions to be used by HAML templates
      # This includes graphql-docs gem helpers class.
      # You can check the included module on: https://github.com/gjtorikian/graphql-docs/blob/v1.6.0/lib/graphql-docs/helpers.rb
      module Helper
        include GraphQLDocs::Helpers

        def auto_generated_comment
          <<-MD.strip_heredoc
            ---
            stage: Plan
            group: Project Management
            info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
            ---

            <!---
              This documentation is auto generated by a script.

              Please do not edit this file directly, check compile_docs task on lib/tasks/gitlab/graphql.rake.
            --->
          MD
        end

        # Template methods:
        # Methods that return chunks of Markdown for insertion into the document

        def render_name_and_description(object, owner: nil, level: 3)
          content = []

          content << "#{'#' * level} `#{object[:name]}`"

          if object[:description].present?
            desc = object[:description].strip
            desc += '.' unless desc.ends_with?('.')
          end

          if object[:is_deprecated]
            owner = Array.wrap(owner)
            deprecation = schema_deprecation(owner, object[:name])
            content << (deprecation&.original_description || desc)
            content << render_deprecation(object, owner, :block)
          else
            content << desc
          end

          content.compact.join("\n\n")
        end

        def render_return_type(query)
          "Returns #{render_field_type(query[:type])}.\n"
        end

        def sorted_by_name(objects)
          return [] unless objects.present?

          objects.sort_by { |o| o[:name] }
        end

        def render_field(field, owner)
          render_row(
            render_name(field, owner),
            render_field_type(field[:type]),
            render_description(field, owner, :inline)
          )
        end

        def render_enum_value(enum, value)
          render_row(render_name(value, enum[:name]), render_description(value, enum[:name], :inline))
        end

        def render_union_member(member)
          "- [`#{member}`](##{member.downcase})"
        end

        # QUERIES:

        # Methods that return parts of the schema, or related information:

        # We are ignoring connections and built in types for now,
        # they should be added when queries are generated.
        def objects
          object_types = graphql_object_types.select do |object_type|
            !object_type[:name]["__"]
          end

          object_types.each do |type|
            type[:fields] += type[:connections]
          end
        end

        def queries
          graphql_operation_types.find { |type| type[:name] == 'Query' }.to_h.values_at(:fields, :connections).flatten
        end

        # We ignore the built-in enum types.
        def enums
          graphql_enum_types.select do |enum_type|
            !enum_type[:name].in?(%w[__DirectiveLocation __TypeKind])
          end
        end

        private # DO NOT CALL THESE METHODS IN TEMPLATES

        # Template methods

        def render_row(*values)
          "| #{values.map { |val| val.to_s.squish }.join(' | ')} |"
        end

        def render_name(object, owner = nil)
          rendered_name = "`#{object[:name]}`"
          rendered_name += ' **{warning-solid}**' if object[:is_deprecated]
          rendered_name
        end

        # Returns the object description. If the object has been deprecated,
        # the deprecation reason will be returned in place of the description.
        def render_description(object, owner = nil, context = :block)
          owner = Array.wrap(owner)
          return render_deprecation(object, owner, context) if object[:is_deprecated]
          return if object[:description].blank?

          desc = object[:description].strip
          desc += '.' unless desc.ends_with?('.')
          desc
        end

        def render_deprecation(object, owner, context)
          deprecation = schema_deprecation(owner, object[:name])
          return deprecation.markdown(context: context) if deprecation

          reason = object[:deprecation_reason] || 'Use of this is deprecated.'
          "**Deprecated:** #{reason}"
        end

        def render_field_type(type)
          "[`#{type[:info]}`](##{type[:name].downcase})"
        end

        # Queries

        # returns the deprecation information for a field or argument
        # See: Gitlab::Graphql::Deprecation
        def schema_deprecation(type_name, field_name)
          schema_member(type_name, field_name)&.deprecation
        end

        # Return a part of the schema.
        #
        # This queries the Schema by owner and name to find:
        #
        # - fields (e.g. `schema_member('Query', 'currentUser')`)
        # - arguments (e.g. `schema_member(['Query', 'project], 'fullPath')`)
        def schema_member(type_name, field_name)
          type_name = Array.wrap(type_name)
          if type_name.size == 2
            arg_name = field_name
            type_name, field_name = type_name
          else
            type_name = type_name.first
            arg_name = nil
          end

          return if type_name.nil? || field_name.nil?

          type = schema.types[type_name]
          return unless type && type.kind.fields?

          field = type.fields[field_name]
          return field if arg_name.nil?

          args = field.arguments
          is_mutation = field.mutation && field.mutation <= ::Mutations::BaseMutation
          args = args['input'].type.unwrap.arguments if is_mutation

          args[arg_name]
        end
      end
    end
  end
end
