# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""The fetch.py and install.py helpers for a 3pp Maven module."""

import os
import pathlib
import re
import shutil
import subprocess
import urllib.request

import common

APACHE_MAVEN_URL = 'https://repo.maven.apache.org/maven2'

_POM_TEMPLATE = """\
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>group</groupId>
  <artifactId>artifact</artifactId>
  <version>1</version>
  <dependencies>
    <dependency>
      <groupId>{group_id}</groupId>
      <artifactId>{artifact_id}</artifactId>
      <version>{version}</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>placeholder_id</id>
      <name>placeholder_name</name>
      <url>{maven_url}</url>
    </repository>
  </repositories>
</project>
"""


def _detect_latest(maven_url, package):
    metadata_url = '{}/{}/maven-metadata.xml'.format(
        maven_url, package.replace('.', '/').replace(':', '/')
    )
    metadata = urllib.request.urlopen(metadata_url).read().decode('utf-8')
    # Do not parse xml with the Python included parser since it is susceptible
    # to maliciously crafted xmls. Only use regular expression parsing to be
    # safe. RE should be enough to handle what we need to extract.
    # TODO(agrieve): Use 'if m := ..." once docker image updates from Python 3.6.
    m = re.search('<latest>([^<]+)</latest>', metadata)
    if m:
        latest = m.group(1)
    else:
        # If no latest info was found just hope the versions are sorted and the
        # last one is the latest (as is commonly the case).
        latest = re.findall('<version>([^<]+)</version>', metadata)[-1]
    return latest


def _install(
    output_prefix,
    deps_prefix,
    maven_url,
    package,
    version,
    jar_name=None,
    post_process_func=None,
):
    # Runs in a docker container.
    group_id, artifact_id = package.split(':')
    if not jar_name:
        jar_name = f'{artifact_id}.jar'

    pathlib.Path('pom.xml').write_text(
        _POM_TEMPLATE.format(
            version=version,
            group_id=group_id,
            artifact_id=artifact_id,
            maven_url=maven_url,
        )
    )

    # Set up JAVA_HOME for the mvn command to find the JDK.
    env = os.environ.copy()
    env['JAVA_HOME'] = common.path_within_checkout('third_party/jdk/current')

    # Ensure that mvn works and the environment is set up correctly.
    subprocess.run(['mvn', '-v'], check=True, env=env)

    # Build the jar file, explicitly specify -f to reduce sources of error.
    subprocess.run(
        ['mvn', 'clean', 'assembly:single', '-f', 'pom.xml'],
        check=True,
        env=env,
    )

    src_jar_path = 'target/artifact-1-jar-with-dependencies.jar'
    dst_jar_path = os.path.join(output_prefix, jar_name)
    if post_process_func:
        post_process_func(src_jar_path, dst_jar_path)
    else:
        shutil.move(src_jar_path, dst_jar_path)


def main(
    *,
    package,
    jar_name=None,
    maven_url='https://dl.google.com/android/maven2',
    post_process_func=None,
    version_override=None,
):
    """3pp entry point for fetch.py.

    Args:
      package: E.g.: some.package:some-thing
      jar_name: Name of .jar. Defaults to |some-thing|.jar
      maven_url: URL of Maven repository.
      post_process_func: Called to finish. Args: src_jar_path, dst_jar_path
      version_override: Use this version instead of the latest one.
    """

    def do_latest():
        return version_override or _detect_latest(maven_url, package)

    def do_install(args):
        _install(
            args.output_prefix,
            args.deps_prefix,
            maven_url,
            package,
            args.version,
            jar_name,
            post_process_func,
        )

    common.main(
        do_latest=do_latest,
        do_install=do_install,
        runtime_deps=['//third_party/jdk/current'],
    )
