# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

from os import path
import datetime
from subprocess import check_output, check_call, CalledProcessError, Popen, PIPE, STDOUT, DEVNULL
import inspect
import os
import sys
# Add both current path to allow us to package import utils and the tools
# dir to allow transitive (for utils) dependencies to be loaded.
sys.path.append(path.dirname(inspect.getfile(lambda: None)))
sys.path.append(
    os.path.join(path.dirname(inspect.getfile(lambda: None)), 'tools'))
from tools.utils import EnsureDepFromGoogleCloudStorage
from tools.jdk import GetJavaExecutable, GetDefaultJdkHome

KOTLIN_FMT_JAR = path.join('third_party', 'google', 'google-kotlin-format',
                           '0.54', 'ktfmt-0.54-jar-with-dependencies.jar')

KOTLIN_FMT_SHA1 = path.join('third_party', 'google', 'google-kotlin-format',
                            '0.54.tar.gz.sha1')

KOTLIN_FMT_IGNORE = {
    'src/test/java/com/android/tools/r8/kotlin/metadata/inline_class_fun_descriptor_classes_app/main.kt'
}
KOTLIN_FMT_BATCH_SIZE = 100

FMT_CMD = path.join('third_party', 'google', 'google-java-format', '1.24.0',
                    'google-java-format-1.24.0', 'scripts',
                    'google-java-format-diff.py')

FMT_CMD_JDK17 = path.join('tools', 'google-java-format-diff.py')
FMT_SHA1 = path.join('third_party', 'google', 'google-java-format',
                     '1.24.0.tar.gz.sha1')

PYTHON_FMT = path.join('third_party', 'google', 'yapf', '20231013')
PYTHON_FMT_EXEC = path.join('third_party', 'google', 'yapf', '20231013', 'yapf')
PYTHON_FMT_SHA1 = path.join('third_party', 'google', 'yapf',
                            '20231013.tar.gz.sha1')

YAPF_PYTHON_PATH = [PYTHON_FMT, os.path.join(PYTHON_FMT, 'third_party')]


def CheckDoNotMerge(input_api, output_api):
    for l in input_api.change.FullDescriptionText().splitlines():
        if l.lower().startswith('do not merge'):
            msg = 'Your cl contains: \'Do not merge\' - this will break WIP bots'
            return [output_api.PresubmitPromptWarning(msg, [])]
    return []


def is_java_extension(file_path):
    return file_path.endswith('.java')


def is_kotlin_extension(file_path):
    return file_path.endswith('.kt') or file_path.endswith('.kts')


def is_python_extension(file_path):
    return file_path.endswith('.py')


def CheckFormatting(input_api, output_api, branch):
    seen_kotlin_error = False
    seen_java_error = False
    seen_python_error = False
    pending_kotlin_files = []
    EnsureDepFromGoogleCloudStorage(KOTLIN_FMT_SHA1,
                                    'google-kotlin-format',
                                    dep=KOTLIN_FMT_JAR)
    EnsureDepFromGoogleCloudStorage(FMT_SHA1, 'google-java-format', dep=FMT_CMD)
    EnsureDepFromGoogleCloudStorage(PYTHON_FMT_SHA1,
                                    'yapf',
                                    dep=PYTHON_FMT_EXEC)
    results = []
    python_runtime = PythonRuntime()
    for f in input_api.AffectedFiles():
        file_path = f.LocalPath()
        if is_kotlin_extension(file_path):
            if file_path in KOTLIN_FMT_IGNORE:
                continue
            pending_kotlin_files.append(file_path)
            if len(pending_kotlin_files) == KOTLIN_FMT_BATCH_SIZE:
                seen_kotlin_error = (CheckKotlinFormatting(
                    pending_kotlin_files, output_api, results) or
                                     seen_kotlin_error)
                pending_kotlin_files = []
        elif is_java_extension(file_path):
            seen_java_error = (CheckJavaFormatting(
                file_path, branch, output_api, results) or seen_java_error)
        elif is_python_extension(file_path):
            seen_python_error = (python_runtime.check_formatting(
                file_path, output_api, results) or seen_python_error)
        else:
            continue
    # Check remaining Kotlin files if any.
    if len(pending_kotlin_files) > 0:
        seen_kotlin_error = (CheckKotlinFormatting(
            pending_kotlin_files, output_api, results) or seen_kotlin_error)
    # Provide the reformatting commands if needed.
    if seen_kotlin_error:
        results.append(output_api.PresubmitError(
            KotlinFormatPresubmitMessage()))
    if seen_java_error:
        results.append(output_api.PresubmitError(JavaFormatPresubmitMessage()))
    if seen_python_error:
        results.append(output_api.PresubmitError(
            PythonFormatPresubmitMessage()))

    # Comment this out to easily fail presubmit changes
    # results.append(output_api.PresubmitError("TESTING"))
    return results


def CheckKotlinFormatting(paths, output_api, results):
    paths_to_format = {
        '--kotlinlang-style': [
            path for path in paths if path.startswith('src/keepanno/')
        ],
        '--google-style': [
            path for path in paths if not path.startswith('src/keepanno/')
        ]
    }
    needs_formatting_count = 0
    for format in ['--kotlinlang-style', '--google-style']:
        cmd = [
            GetJavaExecutable(GetDefaultJdkHome()), '-jar', KOTLIN_FMT_JAR,
            format, '-n'
        ]
        to_format = paths_to_format[format]
        if len(to_format) > 0:
            cmd.extend(to_format)
            result = check_output(cmd)
            if len(result) > 0:
                with_format_error = result.splitlines()
                for path in with_format_error:
                    results.append(
                        output_api.PresubmitError(
                            "File {path} needs formatting".format(
                                path=path.decode('utf-8'))))
            needs_formatting_count += len(result)
    return needs_formatting_count > 0


def KotlinFormatPresubmitMessage():
    return """Please fix the Kotlin formatting by running:

  git diff $(git cl upstream) --name-only "*.kt" "*.kts" | grep -v "^src/keepanno/" | xargs {java} -jar {fmt_jar} --google-style
  git diff $(git cl upstream) --name-only "*.kt" "*.kts" | grep "^src/keepanno/" | xargs {java} -jar {fmt_jar} --kotlinlang-style

or fix formatting, commit and upload:

  git diff $(git cl upstream) --name-only "*.kt" "*.kts" | grep -v "^src/keepanno/" | xargs {java} -jar {fmt_jar} --google-style && git commit -a --amend --no-edit && git cl upload
  git diff $(git cl upstream) --name-only "*.kt" "*.kts" | grep "^src/keepanno/" | xargs {java} -jar {fmt_jar} --kotlinlang-style && git commit -a --amend --no-edit && git cl upload

or bypass the checks with:

  git cl upload --bypass-hooks
    """.format(java=GetJavaExecutable(GetDefaultJdkHome()),
               fmt_jar=KOTLIN_FMT_JAR)


def CheckJavaFormatting(path, branch, output_api, results):
    diff = check_output(
        ['git', 'diff', '--no-prefix', '-U0', branch, '--', path])

    proc = Popen(FMT_CMD, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
    (stdout, stderr) = proc.communicate(input=diff)
    if len(stdout) > 0:
        results.append(output_api.PresubmitError(stdout.decode('utf-8')))
    return len(stdout) > 0


def JavaFormatPresubmitMessage():
    return """Please fix the Java formatting by running:

  git diff -U0 $(git cl upstream) | %s -p1 -i

or fix formatting, commit and upload:

  git diff -U0 $(git cl upstream) | %s -p1 -i && git commit -a --amend --no-edit && git cl upload

or bypass the checks with:

  git cl upload --bypass-hooks

If formatting fails with 'No enum constant javax.lang.model.element.Modifier.SEALED' try

  git diff -U0 $(git cl upstream) | %s %s %s -p1 -i && git commit -a --amend --no-edit && git cl upload
  """ % (
        FMT_CMD, FMT_CMD, FMT_CMD_JDK17, '--google-java-format-jar',
        'third_party/google/google-java-format/1.24.0/google-java-format-1.24.0-all-deps.jar'
    )


def get_env_with_python_path():
    new_env = os.environ.copy()
    new_env['PYTHONPATH'] = ':'.join(YAPF_PYTHON_PATH)
    return new_env


class PythonRuntime:

    def __init__(self):
        self.interpreter = None
        self.has_failed = False

    def initialize_runtime(self):
        # Ensure a python interpreter with platformdirs.
        # This search allows manual setup of .venv.
        python_env = get_env_with_python_path()
        for candidate in [sys.executable, 'python3']:
            try:
                check_call([candidate, '-c', 'import platformdirs'],
                           stdout=DEVNULL,
                           stderr=DEVNULL,
                           env=python_env)
                self.interpreter = candidate
                return None
            except (CalledProcessError, FileNotFoundError):
                continue

        self.has_failed = True
        return (
            "Error: Could not find a Python interpreter with `platformdirs` installed.\n"
            "Please ensure it is installed in your environment:\n"
            "  $ python3 -m venv .venv\n"
            "  $ source .venv/bin/activate\n"
            "  $ pip3 install platformdirs")

    def check_formatting(self, file_path, output_api, results):
        # Avoid repeating initialization errors.
        if self.has_failed:
            return False
        # Initialize interpreter if not done already.
        elif self.interpreter is None:
            init_error = self.initialize_runtime()
            if init_error:
                results.append(output_api.PresubmitError(init_error))
                return True
        format_cmd = [
            self.interpreter, PYTHON_FMT_EXEC, '--diff', '--style', 'google'
        ]
        format_cmd.extend([file_path])

        python_env = get_env_with_python_path()
        format_output = "ill-formatted"
        try:
            format_output = check_output(format_cmd,
                                         env=python_env).decode('utf-8')
        except CalledProcessError as e:
            # --diff returns non-zero if there is a diff
            results.append(output_api.PresubmitError(e.output))
            return True
        return False


def PythonFormatPresubmitMessage():
    return """Please fix the Python formatting by running:

  tools/fmt-diff.py --no-java --no-kotlin --python

or fix formatting, commit and upload:

  tools/fmt-diff.py --no-java --no-kotlin --python && git commit -a --amend --no-edit && git cl upload

or bypass the checks with:

  git cl upload --bypass-hooks
    """


def CheckDeterministicDebuggingChanged(input_api, output_api, branch):
    for f in input_api.AffectedFiles():
        path = f.LocalPath()
        if not path.endswith('InternalOptions.java'):
            continue
        diff = check_output(
            ['git', 'diff', '--no-prefix', '-U0', branch, '--',
             path]).decode('utf-8')
        if 'DETERMINISTIC_DEBUGGING' in diff:
            return [output_api.PresubmitError(diff)]
    return []


def IsTestFile(file):
    localPath = file.LocalPath()
    return is_java_extension(localPath) and '/test/' in localPath


def CheckForAddedDisassemble(input_api, output_api):
    results = []
    for (file, line_nr, line) in input_api.RightHandSideLines():
        if IsTestFile(file) and '.disassemble()' in line:
            results.append(
                output_api.PresubmitError('Test call to disassemble\n%s:%s %s' %
                                          (file.LocalPath(), line_nr, line)))
    return results


def CheckForAddedAllowXxxxxxMessages(input_api, output_api):
    results = []
    for (file, line_nr, line) in input_api.RightHandSideLines():
        if (IsTestFile(file) and ('.allowStdoutMessages()' in line or
                                  '.allowStderrMessages()' in line)):
            results.append(
                output_api.PresubmitError(
                    'Test call to allowStdoutMessages or allowStderrMessages\n%s:%s %s'
                    % (file.LocalPath(), line_nr, line)))
    return results


def CheckForAddedPartialDebug(input_api, output_api):
    results = []
    for (file, line_nr, line) in input_api.RightHandSideLines():
        if not is_java_extension(file.LocalPath()):
            continue
        if '.enablePrintPartialCompilationPartitioning(' in line:
            results.append(
                output_api.PresubmitError(
                    'Test call to enablePrintPartialCompilationPartitioning\n%s:%s %s'
                    % (file.LocalPath(), line_nr, line)))
        if '.setPartialCompilationSeed(' in line:
            results.append(
                output_api.PresubmitError(
                    'Test call to setPartialCompilationSeed\n%s:%s %s' %
                    (file.LocalPath(), line_nr, line)))
    return results


def CheckForCopyright(input_api, output_api, branch):
    results = []
    for f in input_api.AffectedSourceFiles(None):
        # Check if it is a new file.
        if f.OldContents():
            continue
        contents = f.NewContents()
        if (not contents) or (len(contents) == 0):
            continue
        if not CopyrightInContents(f, contents):
            results.append(
                output_api.PresubmitError('Could not find correctly formatted '
                                          'copyright in file: %s' % f))
    return results


def CopyrightInContents(f, contents):
    expected = '//'
    if is_python_extension(f.LocalPath()) or f.LocalPath().endswith('.sh'):
        expected = '#'
    expected = expected + ' Copyright (c) ' + str(datetime.datetime.now().year)
    for content_line in contents:
        if expected in content_line:
            return True
    return False


def CheckLucicfg(input_api, output_api):
    for f in input_api.AffectedFiles():
        if f.LocalPath() == 'infra/config/global/main.star':
            try:
                check_call(
                    ['lucicfg', 'validate', 'infra/config/global/main.star'],
                    stdout=DEVNULL,
                    stderr=STDOUT)
            except CalledProcessError as e:
                return [
                    output_api.PresubmitError(
                        'lucicfg validate infra/config/global/main.star failed')
                ]
            except FileNotFoundError:
                return [output_api.PresubmitError('lucicfg not found in PATH')]
    return []


def CheckChange(input_api, output_api):
    branch = (check_output(['git', 'cl',
                            'upstream']).decode('utf-8').strip().replace(
                                'refs/heads/', ''))
    results = []
    results.extend(CheckDoNotMerge(input_api, output_api))
    results.extend(CheckFormatting(input_api, output_api, branch))
    results.extend(
        CheckDeterministicDebuggingChanged(input_api, output_api, branch))
    results.extend(CheckForAddedDisassemble(input_api, output_api))
    results.extend(CheckForAddedAllowXxxxxxMessages(input_api, output_api))
    results.extend(CheckForAddedPartialDebug(input_api, output_api))
    results.extend(CheckForCopyright(input_api, output_api, branch))
    results.extend(CheckLucicfg(input_api, output_api))
    return results


def CheckChangeOnCommit(input_api, output_api):
    return CheckChange(input_api, output_api)


def CheckChangeOnUpload(input_api, output_api):
    return CheckChange(input_api, output_api)
