#!/usr/bin/env python3
# Copyright (c) 2024, 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.

import historic_run
import perf
import utils

import argparse
import functools
import json
import os
import re
import subprocess
import sys
import time

TARGETS = ['r8-full']
NUM_COMMITS = 1000

FILES = [
    'annotations.js', 'build.html', 'chart.js', 'd8.html', 'dom.js',
    'extensions.js', 'r8.html', 'retrace.html', 'scales.js', 'state.js',
    'stylesheet.css', 'tooltip.js', 'url.js', 'utils.js'
]


def download_cloud_bucket(dest):
    os.makedirs(dest)
    start = time.time()
    utils.download_file_from_cloud_storage(perf.GetGSLocation('*'),
                                           dest,
                                           concurrent=True,
                                           quiet=True,
                                           flags=['-R'])
    end = time.time()
    print("Download bucket finished in %ss" % (end - start))


def get_main_commits():
    top = utils.get_sha1_from_revision('origin/main')
    bottom = utils.get_nth_sha1_from_revision(NUM_COMMITS - 1, 'origin/main')
    commits = historic_run.enumerate_git_commits(top, bottom)
    assert len(commits) == NUM_COMMITS
    return commits


def get_release_branches():
    remote_branches = subprocess.check_output(
        ['git', 'branch', '-r']).decode('utf-8').strip().splitlines()
    result = []
    for remote_branch in remote_branches:
        remote_branch = remote_branch.strip()

        # Strip 'origin/'.
        try:
            remote_name_end_index = remote_branch.index('/')
            remote_branch = remote_branch[remote_name_end_index + 1:]
        except ValueError:
            pass

        # Filter out branches that are not on the form X.Y
        if not re.search(r'^(0|[1-9]\d*)\.(0|[1-9]\d*)$', remote_branch):
            continue

        # Filter out branches prior to 8.9.
        [major, minor] = remote_branch.split('.')
        if int(major) < 8 or (major == '8' and int(minor) < 9):
            continue

        result.append(remote_branch)
    return result


def cmp_versions(x, y):
    semver_x = utils.check_basic_semver_version(x.version(),
                                                allowPrerelease=True)
    semver_y = utils.check_basic_semver_version(y.version(),
                                                allowPrerelease=True)
    if semver_x.larger_than(semver_y):
        return 1
    if semver_y.larger_than(semver_x):
        return -1
    return 0


def get_release_commits():
    release_commits = []
    for branch in get_release_branches():
        (major, minor) = branch.split('.')
        candidate_commits = subprocess.check_output([
            'git', 'log', '--grep=-dev', '--max-count=100',
            '--pretty=format:%H %s', 'origin/' + branch, '--',
            'src/main/java/com/android/tools/r8/Version.java'
        ]).decode('utf-8').strip().splitlines()
        for candidate_commit in candidate_commits:
            separator_index = candidate_commit.index(' ')
            git_hash = candidate_commit[:separator_index]
            git_title = candidate_commit[separator_index + 1:]
            if not re.search(
                    r'^Version %s\.%s\.(0|[1-9]\d*)-dev$' %
                (major, minor), git_title):
                continue
            release_commits.append(historic_run.git_commit_from_hash(git_hash))
    release_commits.sort(key=functools.cmp_to_key(cmp_versions), reverse=True)
    return release_commits


def get_try_commits(local_bucket_try_dict):
    try_commits = []
    seen_try_hashes = set()
    for key, value in local_bucket_try_dict.items():
        # The hash is the 4th component in the path:
        # try/{benchmark}/{target}/{commit.hash()}/{filename}.
        try_hash = key.split('/')[3]
        if try_hash not in seen_try_hashes:
            try_commit = historic_run.git_commit_from_hash(try_hash)
            if try_commit is not None:
                try_commits.append(try_commit)
            seen_try_hashes.add(try_hash)
    return try_commits


def parse_json_from_cloud_storage(filename, local_bucket_dict):
    if not filename in local_bucket_dict:
        return None
    return json.loads(local_bucket_dict[filename])


def record_benchmark_result(commit, benchmark, benchmark_info,
                            local_bucket_dict, target, benchmarks, is_try):
    if not target in benchmark_info['targets']:
        return
    sub_benchmarks = benchmark_info.get('subBenchmarks', {})
    sub_benchmarks_for_target = sub_benchmarks.get(target, [])
    if sub_benchmarks_for_target:
        for sub_benchmark in sub_benchmarks_for_target:
            record_single_benchmark_result(commit, benchmark + sub_benchmark,
                                           local_bucket_dict, target,
                                           benchmarks, is_try)
    else:
        record_single_benchmark_result(commit, benchmark, local_bucket_dict,
                                       target, benchmarks, is_try)


def record_single_benchmark_result(commit, benchmark, local_bucket_dict, target,
                                   benchmarks, is_try):
    if is_try and commit.branch() is not None:
        # Try job has landed on main.
        return
    filename = perf.GetArtifactLocation(benchmark,
                                        target,
                                        commit.hash(),
                                        'result.json',
                                        branch=commit.branch(),
                                        is_try=is_try)
    benchmark_data = parse_json_from_cloud_storage(filename, local_bucket_dict)
    if benchmark_data:
        benchmarks[benchmark] = benchmark_data


def record_benchmark_results(commit, benchmarks, benchmark_data, is_try):
    if benchmarks or benchmark_data:
        data = {
            'author': commit.author_name(),
            'hash': commit.hash(),
            'submitted': commit.committer_timestamp(),
            'title': commit.title(),
            'benchmarks': benchmarks
        }
        if is_try:
            parent_hash = commit.parent_hash()
            try:
                # Find the merge base between the parent commit and origin/main.
                merge_base = subprocess.check_output(
                    ['git', 'merge-base', parent_hash, 'origin/main'],
                    stderr=subprocess.PIPE,
                    text=True).strip()
                data['parent_hash'] = merge_base
            except subprocess.CalledProcessError:
                # Fallback to the direct parent if merge-base fails (e.g., if
                # origin/main doesn't exist or there is no common ancestor).
                data['parent_hash'] = parent_hash
        version = commit.version()
        if version:
            data['version'] = version
        benchmark_data.append(data)


def trim_benchmark_results(benchmark_data):
    new_benchmark_data_len = len(benchmark_data)
    while new_benchmark_data_len > 0:
        candidate_len = new_benchmark_data_len - 1
        if not benchmark_data[candidate_len]['benchmarks']:
            new_benchmark_data_len = candidate_len
        else:
            break
    return benchmark_data[0:new_benchmark_data_len]


def archive_benchmark_results(benchmark_data, dest, outdir, temp):
    # Serialize JSON to temp file.
    benchmark_data_file = os.path.join(temp, dest)
    with open(benchmark_data_file, 'w') as f:
        json.dump(benchmark_data, f)

    # Write output files to public bucket.
    perf.ArchiveOutputFile(benchmark_data_file,
                           dest,
                           header='Cache-Control:no-store',
                           outdir=outdir)


def run_bucket():
    # Get the N most recent commits sorted by newest first.
    main_commits = get_main_commits()

    # Get all release commits from 8.9 and onwards sorted by newest first.
    release_commits = get_release_commits()

    # Download all benchmark data from the cloud bucket to a temp folder.
    with utils.TempDir() as temp:
        local_bucket = os.path.join(temp, perf.BUCKET)
        download_cloud_bucket(local_bucket)
        run(main_commits + release_commits, local_bucket, temp)


def run_local(local_bucket):
    commit_hashes = set()
    for benchmark in os.listdir(local_bucket):
        benchmark_dir = os.path.join(local_bucket, benchmark)
        if benchmark == 'try' or not os.path.isdir(benchmark_dir):
            continue
        for target in os.listdir(benchmark_dir):
            target_dir = os.path.join(local_bucket, benchmark, target)
            if not os.path.isdir(target_dir):
                continue
            for commit_hash in os.listdir(target_dir):
                commit_hash_dir = os.path.join(local_bucket, benchmark, target,
                                               commit_hash)
                if not os.path.isdir(commit_hash_dir):
                    continue
                commit_hashes.add(commit_hash)
    commits = []
    for commit_hash in commit_hashes:
        commits.append(historic_run.git_commit_from_hash(commit_hash))
    commits.sort(key=lambda c: c.committer_timestamp(), reverse=True)
    with utils.TempDir() as temp:
        outdir = os.path.join(utils.TOOLS_DIR, 'perf')
        run(commits, local_bucket, temp, outdir=outdir)


def run(commits, local_bucket, temp, outdir=None):
    print('Loading bucket into memory')
    local_bucket_dict = {}
    local_bucket_try_dict = {}
    for (root, dirs, files) in os.walk(local_bucket):
        for file in files:
            if file != 'result.json':
                continue
            abs_path = os.path.join(root, file)
            rel_path = os.path.relpath(abs_path, local_bucket)
            with open(abs_path, 'r') as f:
                dict_or_try_dict = local_bucket_try_dict if rel_path.startswith(
                    'try/') else local_bucket_dict
                dict_or_try_dict[rel_path] = f.read()

    # Aggregate all the result.json files into a single file that has the
    # same format as tools/perf/benchmark_data.json.
    process_commits(commits, local_bucket_dict, temp, outdir)
    process_commits(get_try_commits(local_bucket_try_dict),
                    local_bucket_try_dict,
                    temp,
                    outdir,
                    is_try=True)

    # Write remaining files to public bucket.
    print('Writing static files')
    if outdir is None:
        for file in FILES:
            dest = os.path.join(utils.TOOLS_DIR, 'perf', file)
            perf.ArchiveOutputFile(dest, file)


def process_commits(commits, local_bucket_dict, temp, outdir, is_try=False):
    print('Processing commits')
    build_benchmark_data = []
    d8_benchmark_data = []
    r8_benchmark_data = []
    retrace_benchmark_data = []
    for commit in commits:
        build_benchmarks = {}
        d8_benchmarks = {}
        r8_benchmarks = {}
        retrace_benchmarks = {}
        for benchmark, benchmark_info in perf.ALL_BENCHMARKS.items():
            record_benchmark_result(commit, benchmark, benchmark_info,
                                    local_bucket_dict, 'build',
                                    build_benchmarks, is_try)
            record_benchmark_result(commit, benchmark, benchmark_info,
                                    local_bucket_dict, 'd8', d8_benchmarks,
                                    is_try)
            record_benchmark_result(commit, benchmark, benchmark_info,
                                    local_bucket_dict, 'r8-full', r8_benchmarks,
                                    is_try)
            record_benchmark_result(commit, benchmark, benchmark_info,
                                    local_bucket_dict, 'retrace',
                                    retrace_benchmarks, is_try)
        record_benchmark_results(commit, build_benchmarks, build_benchmark_data,
                                 is_try)
        record_benchmark_results(commit, d8_benchmarks, d8_benchmark_data,
                                 is_try)
        record_benchmark_results(commit, r8_benchmarks, r8_benchmark_data,
                                 is_try)
        record_benchmark_results(commit, retrace_benchmarks,
                                 retrace_benchmark_data, is_try)

    # Trim data.
    print('Trimming data')
    build_benchmark_data = trim_benchmark_results(build_benchmark_data)
    d8_benchmark_data = trim_benchmark_results(d8_benchmark_data)
    r8_benchmark_data = trim_benchmark_results(r8_benchmark_data)
    retrace_benchmark_data = trim_benchmark_results(retrace_benchmark_data)

    # Write output JSON files to public bucket, or to tools/perf/ if running
    # with --local-bucket.
    print('Writing JSON')
    data_file_suffix = '_try_data.json' if is_try else '_data.json'
    archive_benchmark_results(build_benchmark_data,
                              'build_benchmark' + data_file_suffix, outdir,
                              temp)
    archive_benchmark_results(d8_benchmark_data,
                              'd8_benchmark' + data_file_suffix, outdir, temp)
    archive_benchmark_results(r8_benchmark_data,
                              'r8_benchmark' + data_file_suffix, outdir, temp)
    archive_benchmark_results(retrace_benchmark_data,
                              'retrace_benchmark' + data_file_suffix, outdir,
                              temp)


def parse_options():
    result = argparse.ArgumentParser()
    result.add_argument('--local-bucket', help='Local results dir.')
    return result.parse_known_args()


def main():
    options, args = parse_options()
    if options.local_bucket:
        run_local(options.local_bucket)
    else:
        run_bucket()


if __name__ == '__main__':
    sys.exit(main())
