class Dependabot::Python::FileUpdater::PipfileManifestUpdater

def declaration_regex(dep)

def declaration_regex(dep)
  escaped_name = Regexp.escape(dep.name).gsub("\\-", "[-_.]")
  /(?:^|["'])#{escaped_name}["']?\s*=.*$/i
end

def initialize(dependencies:, manifest:)

def initialize(dependencies:, manifest:)
  @dependencies = dependencies
  @manifest = manifest
end

def requirement_changed?(dependency)

def requirement_changed?(dependency)
  changed_requirements =
    dependency.requirements - T.must(dependency.previous_requirements)
  changed_requirements.any? { |f| f[:file] == manifest.name }
end

def table_declaration_version_regex(dep)

def table_declaration_version_regex(dep)
  /
    packages\.#{Regexp.quote(dep.name)}\]
    (?:(?!^\[).)+
    (?<version_declaration>version\s*=[^\[]*)$
  /mx
end

def update_manifest_req(content:, dep:, old_req:, new_req:)

def update_manifest_req(content:, dep:, old_req:, new_req:)
  simple_declaration = content.scan(declaration_regex(dep))
                              .find { |m| m.include?(old_req) }
  if simple_declaration
    simple_declaration_regex =
      /(?:^|["'])#{Regexp.escape(simple_declaration.to_s)}/
    content.gsub(simple_declaration_regex) do |line|
      line.gsub(old_req, new_req)
    end
  elsif content.match?(table_declaration_version_regex(dep))
    content.gsub(table_declaration_version_regex(dep)) do |part|
      line = T.must(content.match(table_declaration_version_regex(dep)))
              .named_captures.fetch("version_declaration")
      new_line = T.must(line).gsub(old_req, new_req)
      part.gsub(T.must(line), new_line)
    end
  else
    content
  end
end

def update_requirements(content:, dependency:)

def update_requirements(content:, dependency:)
  updated_content = content.dup
  # The UpdateChecker ensures the order of requirements is preserved
  # when updating, so we can zip them together in new/old pairs.
  reqs = dependency.requirements
                   .zip(T.must(dependency.previous_requirements))
                   .reject { |new_req, old_req| new_req == old_req }
  # Loop through each changed requirement
  reqs.each do |new_req, old_req|
    raise "Bad req match" unless new_req[:file] == T.must(old_req)[:file]
    next if new_req[:requirement] == T.must(old_req)[:requirement]
    next unless new_req[:file] == manifest.name
    updated_content = update_manifest_req(
      content: updated_content,
      dep: dependency,
      old_req: T.must(old_req).fetch(:requirement),
      new_req: new_req.fetch(:requirement)
    )
  end
  updated_content
end

def updated_manifest_content

def updated_manifest_content
  dependencies
    .select { |dep| requirement_changed?(dep) }
    .reduce(manifest.content.dup) do |content, dep|
      updated_content = content
      updated_content = update_requirements(
        content: T.must(updated_content),
        dependency: dep
      )
      raise "Content did not change!" if content == updated_content
      updated_content
    end
end