class KPM::NexusFacade::MavenCentralApiCalls

def build_base_path_and_coords(coordinates)

def build_base_path_and_coords(coordinates)
  coords = parse_coordinates(coordinates)
  token_org_and_repo = URI.parse(configuration[:url]).path
  [
    "#{token_org_and_repo}/#{coords[:group_id].gsub('.', '/')}/#{coords[:artifact_id]}",
    "#{coords[:version]}/#{coords[:artifact_id]}-#{coords[:version]}.#{coords[:extension]}",
    coords
  ]
end

def build_download_url(artifact, version, file_name)

def build_download_url(artifact, version, file_name)
  group_path = artifact[:group_id].tr('.', '/')
  "#{BASE_REPO_URL}/#{group_path}/#{artifact[:artifact_id]}/#{version}/#{file_name}"
end

def build_file_name(artifact_id, version, classifier, extension)

def build_file_name(artifact_id, version, classifier, extension)
  classifier ? "#{artifact_id}-#{version}-#{classifier}.#{extension}" : "#{artifact_id}-#{version}.#{extension}"
end

def build_metadata_url(artifact)

def build_metadata_url(artifact)
  group_path = artifact[:group_id].tr('.', '/')
  "#{BASE_REPO_URL}/#{group_path}/#{artifact[:artifact_id]}/maven-metadata.xml"
end

def fetch_latest_version(artifact)

def fetch_latest_version(artifact)
  xml = REXML::Document.new(Net::HTTP.get(URI(build_metadata_url(artifact))))
  xml.elements['//versioning/latest']&.text || xml.elements['//version']&.text
end

def get_artifact_info(coordinates)

def get_artifact_info(coordinates)
  coords = parse_coordinates(coordinates)
  version = coords[:version]
  if version.casecmp('latest').zero?
    version = fetch_latest_version(coords)
    coords = coords.merge(version: version)
  end
  _, versioned_artifact, coords = build_base_path_and_coords([coords[:group_id], coords[:artifact_id], coords[:extension], coords[:classifier], version].compact.join(':'))
  sha1 = get_sha1([coords[:group_id], coords[:artifact_id], coords[:extension], coords[:classifier], version].compact.join(':'))
  artifact_xml = '<artifact-resolution><data>'
  artifact_xml += '<presentLocally>true</presentLocally>'
  artifact_xml += "<groupId>#{coords[:group_id]}</groupId>"
  artifact_xml += "<artifactId>#{coords[:artifact_id]}</artifactId>"
  artifact_xml += "<version>#{coords[:version]}</version>"
  artifact_xml += "<extension>#{coords[:extension]}</extension>"
  artifact_xml += "<snapshot>#{!(coords[:version] =~ /-SNAPSHOT$/).nil?}</snapshot>"
  artifact_xml += "<sha1>#{sha1}</sha1>"
  artifact_xml += "<repositoryPath>/#{coords[:group_id].gsub('.', '/')}/#{versioned_artifact}</repositoryPath>"
  artifact_xml += '</data></artifact-resolution>'
  artifact_xml
end

def get_response(coordinates, endpoint, what_parameters)

def get_response(coordinates, endpoint, what_parameters)
  http = build_http
  query_params = build_query_params(coordinates, what_parameters) unless coordinates.nil?
  endpoint = endpoint_with_params(endpoint, query_params) unless coordinates.nil?
  request = Net::HTTP::Get.new(endpoint)
  if configuration.key?(:username) && configuration.key?(:password)
    request.basic_auth(configuration[:username], configuration[:password])
  elsif configuration.key?(:token)
    request['Authorization'] = "token #{configuration[:token]}"
  end
  logger.debug do
    http.set_debug_output(logger)
    "HTTP path: #{endpoint}"
  end
  http.request(request)
end

def get_response_with_retries(coordinates, endpoint, what_parameters)

def get_response_with_retries(coordinates, endpoint, what_parameters)
  logger.debug { "Fetching coordinates=#{coordinates}, endpoint=#{endpoint}, params=#{what_parameters}" }
  response = get_response(coordinates, endpoint, what_parameters)
  logger.debug { "Response body: #{response.body}" }
  process_response_with_retries(response)
end

def get_sha1(coordinates)

def get_sha1(coordinates)
  base_path, versioned_artifact, = build_base_path_and_coords(coordinates)
  endpoint = "#{base_path}/#{versioned_artifact}.sha1"
  get_response_with_retries(nil, endpoint, nil)
end

def initialize(configuration, _ssl_verify, logger)

def initialize(configuration, _ssl_verify, logger)
  @configuration = configuration
  @configuration[:url] ||= BASE_REPO_URL
  @logger = logger
end

def parse_coordinates(coordinates)

def parse_coordinates(coordinates)
  raise 'Invalid coordinates' if coordinates.nil?
  parts = coordinates.split(':')
  {
    group_id: parts[0],
    artifact_id: parts[1],
    extension: parts.size > 3 ? parts[2] : 'jar',
    classifier: parts.size > 4 ? parts[3] : nil,
    version: parts[-1]
  }
end

def process_response_with_retries(response)

def process_response_with_retries(response)
  case response.code
  when '200'
    response.body
  when '301', '302', '307'
    location = response['Location']
    logger.debug { "Following redirect to #{location}" }
    new_path = location.gsub!(configuration[:url], '')
    if new_path.nil?
      # Redirect to another domain (e.g. CDN)
      get_raw_response_with_retries(location)
    else
      get_response_with_retries(nil, location, nil)
    end
  when '404'
    raise StandardError, ERROR_MESSAGE_404
  else
    raise UnexpectedStatusCodeException, response.code
  end
end

def pull_artifact(coordinates, destination)

def pull_artifact(coordinates, destination)
  artifact = parse_coordinates(coordinates)
  version = artifact[:version]
  version = fetch_latest_version(artifact) if version.casecmp('latest').zero?
  file_name = build_file_name(artifact[:artifact_id], version, artifact[:classifier], artifact[:extension])
  download_url = build_download_url(artifact, version, file_name)
  dest_path = File.join(File.expand_path(destination || '.'), file_name)
  File.open(dest_path, 'wb') do |io|
    io.write(Net::HTTP.get(URI(download_url)))
  end
  {
    file_name: file_name,
    file_path: File.expand_path(dest_path),
    version: version,
    size: File.size(File.expand_path(dest_path))
  }
end

def search_for_artifacts(coordinates)

def search_for_artifacts(coordinates)
  artifact = parse_coordinates(coordinates)
  params = {
    q: "g:\"#{artifact[:group_id]}\" AND a:\"#{artifact[:artifact_id]}\"",
    rows: 200,
    wt: 'json',
    core: 'gav'
  }
  query = params.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
  url = "#{SEARCH_API}?#{query}"
  response = Net::HTTP.get_response(URI(url))
  raise "Search failed: #{response.code}" unless response.code.to_i == 200
  json = JSON.parse(response.body)
  docs = json['response']['docs']
  search_versions = docs.map { |doc| doc['v'] }.uniq
  # Apply when the artifact provided
  if artifact[:artifact_id]
    # Fetch metadata versions (incase the artifact is not indexed)
    metadata_url = build_metadata_url(artifact)
    metadata_versions = []
    begin
      metadata_response = Net::HTTP.get(URI(metadata_url))
      if metadata_response.nil? || metadata_response.strip.empty?
        logger.debug { "Empty metadata response for #{artifact[:artifact_id]}" }
      else
        begin
          metadata_xml = REXML::Document.new(metadata_response)
          metadata_xml.elements.each('//versioning/versions/version') do |version_node|
            metadata_versions << version_node.text
          end
        rescue REXML::ParseException => e
          logger.debug { "Malformed XML in metadata for #{artifact[:artifact_id]}: #{e.message}" }
        end
      end
    rescue StandardError => e
      logger.debug { "Failed to fetch metadata for #{artifact[:artifact_id]}: #{e.message}" }
    end
    # Combine versions
    search_versions = (search_versions + metadata_versions).uniq.sort_by do |v|
      begin
        Gem::Version.new(v)
      rescue ArgumentError
        v
      end
    end.reverse
    artifacts_xml = '<searchNGResponse><data>'
    search_versions.each do |version|
      artifacts_xml += '<artifact>'
      artifacts_xml += "<groupId>#{artifact[:group_id]}</groupId>"
      artifacts_xml += "<artifactId>#{artifact[:artifact_id]}</artifactId>"
      artifacts_xml += "<version>#{version}</version>"
      artifacts_xml += '<repositoryId>central</repositoryId>'
      artifacts_xml += '</artifact>'
    end
  else # Incase no artifact_id is provided for plugin search
    artifacts_xml = '<searchNGResponse><data>'
    docs.each do |doc|
      artifacts_xml += '<artifact>'
      artifacts_xml += "<groupId>#{doc['g']}</groupId>"
      artifacts_xml += "<artifactId>#{doc['a']}</artifactId>"
      artifacts_xml += "<version>#{doc['v']}</version>"
      artifacts_xml += '<repositoryId>central</repositoryId>'
      artifacts_xml += '</artifact>'
    end
  end
  artifacts_xml += '</data></searchNGResponse>'
  artifacts_xml
end