# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

import argparse
import os
import pathlib
import re
import subprocess

import sys
# add parent directory with common methods to python module search path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from common import code_sign

# Use this script so binaries can be distributed and packaged on other computers
# Not idempotent, only run once after recompiling for a specific BuildType (Debug/Release)

def fix_rpath(target_lib):
    otool_cmd = f"otool -l '{target_lib}'| grep RPATH -A2"
    output = subprocess.check_output(otool_cmd, shell=True)
    rpaths = []
    for line in output.decode('utf-8').split("\n"):
        # look for line that matches: path <absolute_path> (offset <number>)
        pattern = "\s*path\s+(\S*)\s+\(offset.*\)\s*"
        match = re.match(pattern, line)
        if match:
            rpath = match.group(1)
            print(f"Removing rpath: {rpath} from {target_lib.name}")
            old_rpath = f"\\{rpath}" if "origin" in rpath.lower() else rpath
            subprocess.run(f"install_name_tool -delete_rpath {old_rpath} {target_lib}", shell=True)

    # add @loader_path as the only rpath, dylibs assume other libs are adjacent to it after this.
    subprocess.run(f'install_name_tool -add_rpath @loader_path {target_lib}', shell=True)

def fix_symlinks(target_lib):
    # aws-cpp-sdk makes a lot of symlinks when you compile it, change rpaths to point to the target of the symlink.
    symlink_dict = {
        "libaws-c-auth.dylib": "libaws-c-auth.1.0.0.dylib",
        "libaws-c-cal.dylib": "libaws-c-cal.1.0.0.dylib",
        "libaws-c-common.1.dylib": "libaws-c-common.1.0.0.dylib",
        "libaws-c-common.dylib": "libaws-c-common.1.dylib",
        "libaws-c-compression.dylib": "libaws-c-compression.1.0.0.dylib",
        "libaws-c-event-stream.dylib": "libaws-c-event-stream.1.0.0.dylib",
        "libaws-c-http.dylib":  "libaws-c-http.1.0.0.dylib",
        "libaws-c-io.dylib": "libaws-c-io.1.0.0.dylib",
        "libaws-c-mqtt.dylib": "libaws-c-mqtt.1.0.0.dylib",
        "libaws-c-s3.0unstable.dylib": "libaws-c-s3.1.0.0.dylib",
        "libaws-c-s3.dylib": "libaws-c-s3.0unstable.dylib",
        "libaws-c-sdkutils.dylib": "libaws-c-sdkutils.1.0.0.dylib",
        "libaws-checksums.dylib": "libaws-checksums.1.0.0.dylib",
    }

    for link, target in symlink_dict.items():
        # Change every dylib link from link to the links target.
        cmd = f"install_name_tool -change @rpath/{link} @rpath/{target} '{target_lib}'"
        try:
            subprocess.run(cmd, shell=True)
        except:
            # Errors are when this lib doesn't depend on target, so ignore.
            pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("type", choices=["Debug", "Release"], help="Compile type for AWS GameKit C++, Debug or Release.")
    parser.add_argument("--certificate_name", default="", help="Common name of the code signing certificate.")
    parser.add_argument("--binaries_dir", help="Directory that contains binaries to fix.")
    args = parser.parse_args()

    script_path = pathlib.Path(__file__).absolute().parent
    repository_root = script_path.parents[1]

    binaries_dir = pathlib.Path(args.binaries_dir)
    for f in binaries_dir.iterdir():
        if not f.is_dir() and str(f.name).startswith("libaws-") and str(f.name).endswith(".dylib"):
            fix_rpath(f)
            fix_symlinks(f)

            if args.certificate_name:
                code_sign(f, args.certificate_name)