# frozen_string_literal: true

module Types
  module Ci
    # This inteface sets [authorize: :read_build] (field-level authorization via
    # JobInterfaceBaseField) for all defined fields to ensure implementing types
    # don't expose inherited fields without proper authorization.
    #
    # Implementing types can opt-out from this field-level auth and use
    # type-level auth by re-defining the field without the authorize argument.
    # For example, JobMinimalAccessType uses :read_build_metadata type-level
    # auth to expose a set of defined fields and leaves inherited fields it does
    # not want to expose to use field-level auth using :read_build.
    module JobInterface
      include BaseInterface

      graphql_name 'CiJobInterface'

      field_class ::Types::Ci::JobInterfaceBaseField

      connection_type_class Types::LimitedCountableConnectionType

      field :active, GraphQL::Types::Boolean, null: true, method: :active?,
        description: 'Indicates the job is active.'
      field :allow_failure, ::GraphQL::Types::Boolean, null: true,
        description: 'Whether the job is allowed to fail.'
      field :artifacts, Types::Ci::JobArtifactType.connection_type, null: true,
        description: 'Artifacts generated by the job.'
      field :browse_artifacts_path, GraphQL::Types::String, null: true,
        description: "URL for browsing the artifact's archive."
      field :cancelable, GraphQL::Types::Boolean, null: true, method: :cancelable?,
        description: 'Indicates the job can be canceled.'
      field :can_play_job, GraphQL::Types::Boolean,
        null: true, resolver_method: :can_play_job?,
        description: 'Indicates whether the current user can play the job.',
        calls_gitaly: true
      field :commit_path, GraphQL::Types::String, null: true,
        description: 'Path to the commit that triggered the job.'
      field :created_at, Types::TimeType, null: true,
        description: "When the job was created."
      field :coverage, GraphQL::Types::Float, null: true,
        description: 'Coverage level of the job.'
      field :created_by_tag, GraphQL::Types::Boolean, null: true,
        description: 'Whether the job was created by a tag.', method: :tag?
      field :detailed_status, Types::Ci::DetailedStatusType, null: true,
        description: 'Detailed status of the job.'
      field :duration, GraphQL::Types::Int, null: true,
        description: 'Duration of the job in seconds.'
      field :erased_at, Types::TimeType, null: true,
        description: "When the job was erased."
      # rubocop:disable Layout/LineLength -- otherwise description is creating unnecessary newlines.
      field :exit_code, GraphQL::Types::Int, null: true,
        description: 'Exit code of the job. Available for jobs that started after upgrading to GitLab 16.10 and failed with an exit code.'
      # rubocop:enable Layout/LineLength
      field :failure_message, GraphQL::Types::String, null: true,
        description: 'Message on why the job failed.'
      field :finished_at, Types::TimeType, null: true,
        description: 'When a job has finished running.'
      field :id, ::Types::GlobalIDType[::CommitStatus].as('JobID'), null: true,
        description: 'ID of the job.'
      field :kind, type: ::Types::Ci::JobKindEnum, null: true,
        description: 'Indicates the type of job.'
      field :manual_job, GraphQL::Types::Boolean, null: true,
        description: 'Whether the job has a manual action.'
      field :name, GraphQL::Types::String, null: true,
        description: 'Name of the job.'
      field :pipeline, Types::Ci::PipelineInterface, null: true,
        description: 'Pipeline the job belongs to.'
      field :playable, GraphQL::Types::Boolean, null: true, method: :playable?,
        description: 'Indicates the job can be played.'
      field :play_path, GraphQL::Types::String, null: true,
        description: 'Play path of the job.'
      field :project, Types::Projects::ProjectInterface, null: true, description: 'Project that the job belongs to.'
      field :queued_at, Types::TimeType, null: true,
        description: 'When the job was enqueued and marked as pending.'
      field :queued_duration,
        type: Types::DurationType,
        null: true,
        description: 'How long the job was enqueued before starting.'
      field :ref_name, GraphQL::Types::String, null: true,
        description: 'Ref name of the job.'
      field :ref_path, GraphQL::Types::String, null: true,
        description: 'Path to the ref.'
      field :retried, GraphQL::Types::Boolean, null: true,
        description: 'Indicates that the job has been retried.'
      field :retryable, GraphQL::Types::Boolean, null: true,
        description: 'Indicates the job can be retried.'
      field :retry_path, GraphQL::Types::String, null: true,
        description: 'Retry path of the job.'
      field :runner, Types::Ci::RunnerType, null: true, description: 'Runner assigned to execute the job.'
      field :scheduled, GraphQL::Types::Boolean, null: true, method: :scheduled?,
        description: 'Indicates the job is scheduled.'
      field :scheduled_at, Types::TimeType, null: true,
        description: 'Schedule for the build.'
      # rubocop:disable Layout/LineLength -- otherwise description is creating unnecessary newlines.
      field :scheduling_type, GraphQL::Types::String, null: true,
        description: 'Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise.'
      # rubocop:enable Layout/LineLength
      field :short_sha, type: GraphQL::Types::String, null: true,
        description: 'Short SHA1 ID of the commit.'
      field :source, GraphQL::Types::String, null: true,
        description: 'Policy or action that initiated the job. If not set, the value is inherited from the pipeline.'
      field :stage, Types::Ci::StageType, null: true,
        description: 'Stage of the job.'
      field :started_at, Types::TimeType, null: true,
        description: 'When the job was started.'
      field :status,
        type: ::Types::Ci::JobStatusEnum,
        null: true,
        description: "Status of the job."
      field :stuck, GraphQL::Types::Boolean, null: true, method: :stuck?,
        description: 'Indicates the job is stuck.'
      field :tags, [GraphQL::Types::String], null: true,
        description: 'Tags for the current job.'
      field :trace, Types::Ci::JobTraceType, null: true,
        description: 'Trace generated by the job.'
      field :triggered, GraphQL::Types::Boolean, null: true,
        description: 'Whether the job was triggered.'
      field :user_permissions, Types::PermissionTypes::Ci::Job,
        description: 'Permissions for the current user on the job.',
        null: true,
        method: :itself
      field :web_path, GraphQL::Types::String, null: true,
        description: 'Web path of the job.'

      def detailed_status
        object.detailed_status(context[:current_user])
      end

      def manual_job
        object.try(:action?)
      end

      def ref_name
        object&.ref
      end

      def triggered
        object.pipeline.trigger_id.present?
      end

      def self.resolve_type(_object, _context)
        ::Types::Ci::JobType
      end
    end
  end
end

Types::Ci::JobInterface.prepend_mod
