class Dependabot::PullRequestCreator::Gitlab

def add_approvers_to_merge_request(merge_request)

def add_approvers_to_merge_request(merge_request)
  return unless approvers_hash[:approvers] || approvers_hash[:group_approvers]
  T.unsafe(gitlab_client_for_source).create_merge_request_level_rule(
    target_project_id || source.repo,
    T.unsafe(merge_request).iid,
    name: "dependency-updates",
    approvals_required: 1,
    user_ids: approvers_hash[:approvers],
    group_ids: approvers_hash[:group_approvers]
  )
end

def annotate_merge_request(merge_request)

def annotate_merge_request(merge_request)
  add_approvers_to_merge_request(merge_request)
end

def approvers_hash

def approvers_hash
  @approvers_hash ||= T.let(
    approvers || {},
    T.nilable(T::Hash[Symbol, T::Array[Integer]])
  )
end

def branch_exists?

def branch_exists?
  @branch_ref ||=
    T.let(
      T.unsafe(gitlab_client_for_source).branch(source.repo, branch_name),
      T.nilable(::Gitlab::ObjectifiedHash)
    )
  true
rescue ::Gitlab::Error::NotFound
  false
end

def commit_exists?

def commit_exists?
  @commits ||=
    T.let(
      T.unsafe(gitlab_client_for_source).commits(source.repo, ref_name: branch_name),
      T.nilable(::Gitlab::PaginatedResponse)
    )
  @commits.first.message == commit_message
end

def create

def create
  return if branch_exists? && merge_request_exists?
  if branch_exists?
    create_commit unless commit_exists?
  else
    create_branch
    create_commit
  end
  labeler.create_default_labels_if_required
  merge_request = create_merge_request
  return unless merge_request
  annotate_merge_request(merge_request)
  merge_request
end

def create_branch

def create_branch
  T.unsafe(gitlab_client_for_source).create_branch(
    source.repo,
    branch_name,
    base_commit
  )
end

def create_commit

def create_commit
  return create_submodule_update_commit if files.count == 1 && T.must(files.first).type == "submodule"
  options = {}
  options[:author_email] = author_details&.fetch(:email) if author_details&.key?(:email)
  options[:author_name] = author_details&.fetch(:name) if author_details&.key?(:name)
  gitlab_client_for_source.create_commit(
    source.repo,
    branch_name,
    commit_message,
    files,
    **options
  )
end

def create_merge_request

def create_merge_request
  T.unsafe(gitlab_client_for_source).create_merge_request(
    source.repo,
    pr_name,
    source_branch: branch_name,
    target_branch: source.branch || default_branch,
    description: pr_description,
    remove_source_branch: true,
    assignee_ids: assignees,
    labels: labeler.labels_for_pr.join(","),
    milestone_id: milestone,
    target_project_id: target_project_id,
    reviewer_ids: approvers_hash[:reviewers]
  )
end

def create_submodule_update_commit

def create_submodule_update_commit
  file = T.must(files.first)
  T.unsafe(gitlab_client_for_source).edit_submodule(
    source.repo,
    file.path.gsub(%r{^/}, ""),
    branch: branch_name,
    commit_sha: file.content,
    commit_message: commit_message
  )
end

def default_branch

def default_branch
  @default_branch ||=
    T.let(
      T.unsafe(gitlab_client_for_source).project(source.repo).default_branch,
      T.nilable(String)
    )
end

def gitlab_client_for_source

def gitlab_client_for_source
  @gitlab_client_for_source ||=
    T.let(
      Dependabot::Clients::GitlabWithRetries.for_source(
        source: source,
        credentials: credentials
      ),
      T.nilable(Dependabot::Clients::GitlabWithRetries)
    )
end

def initialize(source:, branch_name:, base_commit:, credentials:,

def initialize(source:, branch_name:, base_commit:, credentials:,
               files:, commit_message:, pr_description:, pr_name:,
               author_details:, labeler:, approvers:, assignees:,
               milestone:, target_project_id:)
  @source            = source
  @branch_name       = branch_name
  @base_commit       = base_commit
  @credentials       = credentials
  @files             = files
  @commit_message    = commit_message
  @pr_description    = pr_description
  @pr_name           = pr_name
  @author_details    = author_details
  @labeler           = labeler
  @approvers         = approvers
  @assignees         = assignees
  @milestone         = milestone
  @target_project_id = target_project_id
end

def merge_request_exists?

def merge_request_exists?
  T.unsafe(gitlab_client_for_source).merge_requests(
    target_project_id || source.repo,
    source_branch: branch_name,
    target_branch: source.branch || default_branch,
    state: "all"
  ).any?
end