class Dependabot::PullRequestCreator::Codecommit

def base_commit_is_up_to_date?

def base_commit_is_up_to_date?
  codecommit_client_for_source.fetch_commit(
    source.repo,
    branch_name
  ) == base_commit
end

def branch_exists?(branch_name)

def branch_exists?(branch_name)
  @branch_ref ||= T.let(
    codecommit_client_for_source.branch(branch_name),
    T.nilable(String)
  )
  !@branch_ref.nil?
  rescue Aws::CodeCommit::Errors::BranchDoesNotExistException
    false
end

def codecommit_client_for_source

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

def create

def create
  return if branch_exists?(branch_name) && unmerged_pull_request_exists?
  return if require_up_to_date_base? && !base_commit_is_up_to_date?
  create_pull_request
end

def create_branch(commit)

def create_branch(commit)
  # codecommit returns an empty response on create branch success
  codecommit_client_for_source.create_branch(source.repo, branch_name,
                                             commit)
  @branch_name = branch_name
  branch_name
end

def create_commit

def create_commit
  author_name = author_details&.fetch(:name)
  codecommit_client_for_source.create_commit(
    branch_name,
    author_name,
    base_commit,
    commit_message,
    files
  )
end

def create_or_get_branch(commit)

def create_or_get_branch(commit)
  # returns the branch name
  if branch_exists?(branch_name)
    branch_name
  else
    create_branch(commit)
  end
end

def create_pull_request

def create_pull_request
  branch = create_or_get_branch(base_commit)
  return unless branch
  create_commit
  pull_request = codecommit_client_for_source.create_pull_request(
    pr_name,
    branch_name,
    source.branch || default_branch,
    pr_description
    # codecommit doesn't support PR labels
  )
  return unless pull_request
  pull_request
end

def default_branch

def default_branch
  @default_branch ||=
    T.let(
      codecommit_client_for_source.fetch_default_branch(source.repo),
      T.nilable(String)
    )
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:, require_up_to_date_base:)
  @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
  @require_up_to_date_base = require_up_to_date_base
end

def pull_requests_for_branch

def pull_requests_for_branch
  @pull_requests_for_branch ||=
    T.let(
      begin
        open_prs = codecommit_client_for_source.pull_requests(
          source.repo,
          "open",
          source.branch || default_branch
        )
        closed_prs = codecommit_client_for_source.pull_requests(
          source.repo,
          "closed",
          source.branch || default_branch
        )
        [*open_prs, *closed_prs]
      end,
      T.nilable(T::Array[Aws::CodeCommit::Types::PullRequest])
    )
end

def require_up_to_date_base?

def require_up_to_date_base?
  @require_up_to_date_base
end

def unmerged_pull_request_exists?

def unmerged_pull_request_exists?
  unmerged_prs = []
  pull_requests_for_branch.each do |pr|
    unless T.unsafe(pr).pull_request
            .pull_request_targets[0].merge_metadata.is_merged
      unmerged_prs << pr
    end
  end
  unmerged_prs.any?
end