#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import errno
import logging
import os
import re
import subprocess
import sys
"""
This Python script is used for upgrading the GCP-BOM in BeamModulePlugin.
Specifically, it

1. preprocessing BeamModulePlugin.groovy to decide the dependencies need to sync
2. generate an empty Maven project to fetch the exact target versions to change
3. Write back to BeamModulePlugin.groovy
4. Update libraries-bom version on sdks/java/container/license_scripts/dep_urls_java.yaml

There are few reasons we need to declare the version numbers:
1. Sync the dependency that not included in GCP-BOM with those included with BOM
  For example, "com.google.cloud:google-cloud-spanner" does while "com.google.cloud:google-cloud-spanner:():test" doesn't
2. There are Beam artifacts not depending on GCP-BOM but used dependency managed
  by GCP-BOM.

Refer to https://github.com/googleapis/java-cloud-bom/tags for the dependency
versions managed by gcp-cloud-bom
"""

# To format: yapf --style sdks/python/setup.cfg --in-place scripts/tools/bomupgrader.py


class BeamModulePluginProcessor:
  # Known dependencies managed by GCP BOM and also used by Beam.
  # We only need to have one dependency for each project to figure out the target version
  KNOWN_DEPS = {
      "arrow": "org.apache.arrow:arrow-memory-core",
      "gax": "com.google.api:gax",
      "google_cloud_spanner": "com.google.cloud:google-cloud-spanner",
      "grpc":
          "io.grpc:grpc-netty",  # use "grpc-netty" to pick up proper netty version
      "netty": "io.netty:netty-transport",
      "opentelemetry": "io.opentelemetry:opentelemetry-sdk",
      "protobuf": "com.google.protobuf:protobuf-java"
  }
  # dependencies managed by GCP-BOM that used the dependencies in KNOWN_DEPS
  # So we need to add it to the example project to get the version to sync
  OTHER_CONSTRANTS = [
      "com.google.cloud:google-cloud-bigquery",  # for arrow
      'com.google.cloud:google-cloud-storage',  # for google-api-services-storage
      'com.google.cloud:google-cloud-resourcemanager',  # for google-api-services-cloudresourcemanager
      'com.google.cloud:google-cloud-datastore',  # for google-cloud-dataflow-java-proto-library-all
  ]

  # TODO: the logic can be generalized to support multiple BOM
  ANCHOR = re.compile(
      r'\s*//\s*\[bomupgrader\] determined by: (\S+), consistent with: google_cloud_platform_libraries_bom'
  )
  # e.g.  def grpc_version = "1.61.0"
  VERSION_STRING = re.compile(r'^\s*def (\w+)_version\s*=\s*[\'"](\S+)[\'"]')
  SINGLE_VERSION_STRING = re.compile(
      r'.+:\s*[\'"]([\w\-.]+:[\w\-.]+):(.+)[\'"],\s*//\s*\[bomupgrader\] sets version'
  )
  BOM_VERSION_STRING = re.compile(
      r'\s*google_cloud_platform_libraries_bom\s*:\s*[\'"]com\.google\.cloud:libraries-bom:([0-9\.]+)[\'"],?'
  )
  BUILD_DIR = 'build/dependencyResolver'
  BEAMMPLG_PATH = 'buildSrc/src/main/groovy/org/apache/beam/gradle/BeamModulePlugin.groovy'
  LICENSE_SC_PATH = 'sdks/java/container/license_scripts/dep_urls_java.yaml'
  GRADLE_TEMPLATE = """
plugins { id 'java' }
repositories { mavenCentral() }
dependencies {
implementation platform('com.google.cloud:libraries-bom:%s')
%s
}
configurations.implementation.canBeResolved = true
"""

  def __init__(self, bom_version, project_root='.', runnable=None):
    self.bom_version = bom_version
    self.project_root = project_root
    self.runnable = runnable or os.path.abspath('gradlew')
    logging.info('-----Read BeamModulePlugin-----')
    with open(os.path.join(project_root, self.BEAMMPLG_PATH), 'r') as fin:
      self.original_lines = fin.readlines()
    # e.g. {"io.grpc:grpc-netty", "1.61.0"}
    self.dep_versions = {}
    self.dep_versions_current = {}
    # dependencies managed by bomupgrader. They are declared inline in BeamModulePlugin,
    # different from KNOWN_DEPS which first define a version
    self.set_deps = {}
    self.set_deps_current = {}

  @staticmethod
  def resolve_actual_dep(line, id):
    """Resolve actual dependency from dependencyTree line"""
    idx = line.find(id + ':')
    if idx == -1: return ""  # not found
    dep_and_other = line[idx + len(id) + 1:].split()
    try:
      jdx = dep_and_other.index('->')
      ver = dep_and_other[jdx + 1]
    except ValueError:
      # there might be multiple ':', e.g. come.group.id:some-package:test:1.2.3
      ver = dep_and_other[0].split(':')[-1]
    return ver

  def check_dependencies(self):
    """Check dependencies in KNOWN_DEPS are found in BeamModulePlugin, and vice versa."""
    logging.info("-----check dependency defs in BeamModulePlugin-----")
    found_deps = {}
    for idx, line in enumerate(self.original_lines):
      m = self.ANCHOR.match(line)
      if m:
        n = self.VERSION_STRING.search(self.original_lines[idx + 1])
        if not n:
          raise RuntimeError(
              "Version definition not found after anchor comment. Try standardize it."
          )
        found_deps[n.group(1)] = n.group(2)
        continue
      m = self.SINGLE_VERSION_STRING.match(line)
      if m:
        self.set_deps_current[m.group(1)] = m.group(2)

    assert sorted(self.KNOWN_DEPS.keys()) == sorted(found_deps.keys()), f"expect {self.KNOWN_DEPS.keys()} == {found_deps.keys()}"
    self.dep_versions_current = {
        self.KNOWN_DEPS[k]: v
        for k, v in found_deps.items()
    }

  def prepare_gradle(self, bom_version):
    logging.info("-----prepare build.gradle for example project-----")
    try:
      os.makedirs(self.BUILD_DIR)
    except OSError as e:
      if e.errno != errno.EEXIST:
        raise

    deps = []
    for dep in list(self.KNOWN_DEPS.values()) + self.OTHER_CONSTRANTS + list(
        self.set_deps_current.keys()):
      deps.append(f"implementation '{dep}'")
    gradle_file = self.GRADLE_TEMPLATE % (bom_version, "\n".join(deps))
    with open(os.path.join(self.BUILD_DIR, 'build.gradle'), 'w') as fout:
      fout.write(gradle_file)
    # we need a settings.gradle
    with open(os.path.join(self.BUILD_DIR, 'settings.gradle'), 'w') as fout:
      fout.write('\n')

  def resolve(self):
    logging.info("-----resolve dependency-----")
    subp = subprocess.run([
        self.runnable,
        *(
            '-q dependencies --configuration implementation --console=plain'.
            split())
    ],
                          cwd=self.BUILD_DIR,
                          stdout=subprocess.PIPE)

    result = subp.stdout.decode('utf-8')
    # example line: |    +--- com.google.guava:guava:32.1.3-android -> 32.1.3-jre (*)
    logging.debug(result)
    get_dep_line = re.compile('\s+([\w\-.]+:[\w\-.]+):(.+)')

    for line in result.splitlines():
      # search self.set_deps version
      m = get_dep_line.search(line)
      if m and m.group(1) in self.set_deps_current:
        ver = self.resolve_actual_dep(line, m.group(1))
        self.set_deps[m.group(1)] = ver
        continue

      # search KNOWN_DEPS version
      for id in self.KNOWN_DEPS.values():
        if id in self.dep_versions: continue
        ver = self.resolve_actual_dep(line, id)
        if ver:
          self.dep_versions[id] = ver
          break

    if len(self.dep_versions) < len(self.KNOWN_DEPS):
      logging.warning(
          "Warning: not all dependencies are resolved: %s", self.dep_versions)
      logging.info(result)

    if len(self.set_deps) < len(self.set_deps_current):
      logging.warning(
          "Warning: not all dependencies are resolved: %s", self.set_deps)
      logging.info(result)

  def write_back(self):
    logging.info("-----Update BeamModulePlugin-----")
    # make a shallow copy
    self.target_lines = list(self.original_lines)
    found_bom = False

    for idx, line in enumerate(self.original_lines):
      m = self.ANCHOR.match(line)
      if m:
        n = self.VERSION_STRING.search(self.original_lines[idx + 1])
        if not n:
          raise RuntimeError(
              "Version definition not found after anchor comment. Try standardize it."
          )
        id = self.KNOWN_DEPS[n.group(1)]
        new_v = self.dep_versions[id]
        old_v = self.dep_versions_current[id]
        if new_v != old_v:
          self.target_lines[idx + 1] = self.original_lines[idx + 1].replace(
              old_v, new_v)
          logging.info('Changed %s: %s -> %s', id, old_v, new_v)
        else:
          logging.info('Unchanged: %s:%s', id, new_v)
        continue

      # single_ver replace
      m = self.SINGLE_VERSION_STRING.match(line)
      if m:
        id = m.group(1)
        old_v = m.group(2)
        new_v = self.set_deps[id]
        if new_v != old_v:
          self.target_lines[idx] = self.original_lines[idx].replace(
              old_v, new_v)
          logging.info('Changed %s: %s -> %s', id, old_v, new_v)
        else:
          logging.info('Unchanged: %s:%s', id, new_v)
      # replace GCP BOM version
      n = self.BOM_VERSION_STRING.match(line)
      if n:
        self.target_lines[idx] = self.original_lines[idx].replace(
            n.group(1), self.bom_version)
        found_bom = True

    if not found_bom:
      logging.warning(
          'GCP_BOM version declaration not found in BeamModulePlugin')

    with open(os.path.join(self.project_root, self.BEAMMPLG_PATH), 'w') as fout:
      for line in self.target_lines:
        fout.write(line)

  def write_license_script(self):
    logging.info("-----Update dep_urls_java.yaml-----")
    with open(os.path.join(self.project_root, self.LICENSE_SC_PATH),
              'r') as fin:
      lines = fin.readlines()
    with open(os.path.join(self.project_root, self.LICENSE_SC_PATH),
              'w') as fout:
      for idx, line in enumerate(lines):
        if line.strip() == 'libraries-bom:':
          lines[idx + 1] = re.sub(
              r'[\'"]\d[\.\d]+[\'"]', f"'{self.bom_version}'", lines[idx + 1])
        fout.write(line)

  def run(self):
    self.check_dependencies()
    self.prepare_gradle(self.bom_version)
    self.resolve()
    self.write_back()
    self.write_license_script()


if __name__ == '__main__':
  logging.getLogger().setLevel(logging.INFO)
  if len(sys.argv) < 2:
    print("Usage: python scripts/tools/bomupgrader.py target_version")
    exit(1)
  processor = BeamModulePluginProcessor(sys.argv[1])
  processor.run()
