class Dependabot::PullRequestCreator::BranchNamer::SoloStrategy

def branch_name_might_be_long?

def branch_name_might_be_long?
  dependencies.count > 1 && !updating_a_property? && !updating_a_dependency_set?
end

def branch_version_suffix

def branch_version_suffix
  dep = T.must(dependencies.first)
  if dep.removed?
    "-removed"
  elsif library? && ref_changed?(dep) && new_ref(dep)
    new_ref(dep)
  elsif library?
    sanitized_requirement(dep)
  else
    new_version(dep)
  end
end

def dependency_digest

def dependency_digest
  T.let(
    Digest::MD5.hexdigest(
      dependencies.map do |dependency|
        "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
      end.sort.join(",")
    ).slice(0, 10),
    T.nilable(String)
  )
end

def dependency_set

def dependency_set
  @dependency_set ||=
    T.let(
      T.must(dependencies.first).requirements
                         .find { |r| r.dig(:metadata, :dependency_set) }
                         &.dig(:metadata, :dependency_set),
      T.nilable(T::Hash[String, String])
    )
  raise "No dependency set!" unless @dependency_set
  @dependency_set
end

def library?

def library?
  dependencies.any? { |d| !d.appears_in_lockfile? }
end

def new_branch_name

def new_branch_name
  return short_branch_name if branch_name_might_be_long?
  @name ||=
    T.let(
      begin
        dependency_name_part =
          if dependencies.count > 1 && updating_a_property?
            property_name
          elsif dependencies.count > 1 && updating_a_dependency_set?
            dependency_set.fetch(:group)
          else
            dependencies
              .map(&:name)
              .join("-and-")
              .tr(":[]", "-")
              .tr("@", "")
          end
        "#{dependency_name_part}-#{branch_version_suffix}"
      end,
      T.nilable(String)
    )
  sanitize_branch_name(File.join(prefixes, @name))
end

def new_library_requirement(dependency)

def new_library_requirement(dependency)
  updated_reqs =
    dependency.requirements - T.must(dependency.previous_requirements)
  gemspec =
    updated_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) }
  return gemspec[:requirement] if gemspec
  updated_reqs.first&.fetch(:requirement)
end

def new_ref(dependency)

def new_ref(dependency)
  new_refs = dependency.requirements.filter_map do |r|
    r.dig(:source, "ref") || r.dig(:source, :ref)
  end.uniq
  new_refs.first if new_refs.one?
end

def new_version(dependency)

def new_version(dependency)
  # Version looks like a git SHA and we could be updating to a specific
  # ref in which case we return that otherwise we return a shorthand sha
  if dependency.version&.match?(/^[0-9a-f]{40}$/)
    return new_ref(dependency) if ref_changed?(dependency) && new_ref(dependency)
    T.must(dependency.version)[0..6]
  elsif dependency.version == dependency.previous_version &&
        package_manager == "docker"
    dependency.requirements
              .filter_map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }
              .first.split(":").last[0..6]
  else
    dependency.version
  end
end

def package_manager

def package_manager
  T.must(dependencies.first).package_manager
end

def prefixes

def prefixes
  [
    prefix,
    package_manager,
    files.first&.directory&.tr(" ", "-"),
    target_branch
  ].compact
end

def previous_ref(dependency)

def previous_ref(dependency)
  previous_refs = T.must(dependency.previous_requirements).filter_map do |r|
    r.dig(:source, "ref") || r.dig(:source, :ref)
  end.uniq
  previous_refs.first if previous_refs.one?
end

def property_name

def property_name
  @property_name ||=
    T.let(
      T.must(dependencies.first).requirements
                                      .find { |r| r.dig(:metadata, :property_name) }
                                      &.dig(:metadata, :property_name),
      T.nilable(String)
    )
  raise "No property name!" unless @property_name
  @property_name
end

def ref_changed?(dependency)

def ref_changed?(dependency)
  # We could go from multiple previous refs (nil) to a single new ref
  previous_ref(dependency) != new_ref(dependency)
end

def requirements_changed?(dependency)

def requirements_changed?(dependency)
  (dependency.requirements - T.must(dependency.previous_requirements)).any?
end

def sanitized_requirement(dependency)

def sanitized_requirement(dependency)
  new_library_requirement(dependency)
    .delete(" ")
    .gsub("!=", "neq-")
    .gsub(">=", "gte-")
    .gsub("<=", "lte-")
    .gsub("~>", "tw-")
    .gsub("^", "tw-")
    .gsub("||", "or-")
    .gsub("~", "approx-")
    .gsub("~=", "tw-")
    .gsub(/==*/, "eq-")
    .gsub(">", "gt-")
    .gsub("<", "lt-")
    .gsub("*", "star")
    .gsub(",", "-and-")
end

def short_branch_name

def short_branch_name
  # Fix long branch names by using a digest of the dependencies instead of their names.
  sanitize_branch_name(File.join(prefixes, "multi-#{dependency_digest}"))
end

def updating_a_dependency_set?

def updating_a_dependency_set?
  T.must(dependencies.first)
   .requirements
   .any? { |r| r.dig(:metadata, :dependency_set) }
end

def updating_a_property?

def updating_a_property?
  T.must(dependencies.first)
   .requirements
   .any? { |r| r.dig(:metadata, :property_name) }
end