import argparse
import os
import shutil
import tarfile
import tempfile


def get_sys_arch_list():
    return [
        ('darwin', ['universal2']),
        ('linux', ['aarch64', 'x86_64']),
        ('windows', ['x86_64']),
    ]


def prepare_app(src_dir: str, dst_dir: str, release_version: str):
    for system, archs in get_sys_arch_list():
        bin_suff = '.exe' if system == 'windows' else ''
        for arch in archs:
            os.rename(
                os.path.join(src_dir, f'bin_{system}-{arch}', 'catboost' + bin_suff),
                os.path.join(dst_dir, f'catboost-{system}-{arch}-{release_version}{bin_suff}')
            )

    # legacy names for compatibility
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-windows-x86_64-{release_version}.exe'),
        os.path.join(dst_dir, f'catboost-{release_version}.exe')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-darwin-universal2-{release_version}'),
        os.path.join(dst_dir, f'catboost-darwin-{release_version}')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-linux-x86_64-{release_version}'),
        os.path.join(dst_dir, f'catboost-linux-{release_version}')
    )

def extract_file_from_tgz(src_tgz_path: str, tar_member: str, dst_path: str, tmp_dir: str):
    with tarfile.open(src_tgz_path, "r:gz") as tar:
        needed_members = [m for m in tar.getmembers() if m.name == tar_member]
        tar.extractall(members=needed_members, path=tmp_dir)
        os.rename(os.path.join(tmp_dir, tar_member), dst_path)

def prepare_R_package(src_dir: str, dst_dir: str, release_version: str, tmp_dir: str):
    for system, archs in get_sys_arch_list():
        for arch in archs:
            dst_tgz = os.path.join(dst_dir, f'catboost-R-{system}-{arch}-{release_version}.tgz')
            os.rename(os.path.join(src_dir, 'R', f'catboost-R-{system}-{arch}.tgz'), dst_tgz)

            # extract so only
            if system == 'windows':
                so_path_in_tgz = 'catboost/inst/libs/x64/libcatboostr.dll'
                dst_suffix = '.dll'
            else:
                so_path_in_tgz = 'catboost/inst/libs/libcatboostr.so'

                # there's a confusion what is the proper suffix for R packages binaries on Darwin (.so or .dylib),
                # but R-package/R/install.R uses .dylib to fetch artifacts
                dst_suffix = '.dylib' if system == 'darwin' else '.so'

            extract_file_from_tgz(
                dst_tgz,
                so_path_in_tgz,
                os.path.join(dst_dir, f'libcatboostr-{system}-{arch}-{release_version}{dst_suffix}'),
                tmp_dir
            )


    # legacy names for compatibility
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-R-darwin-universal2-{release_version}.tgz'),
        os.path.join(dst_dir, f'catboost-R-Darwin-{release_version}.tgz')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-R-linux-x86_64-{release_version}.tgz'),
        os.path.join(dst_dir, f'catboost-R-Linux-{release_version}.tgz')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'catboost-R-windows-x86_64-{release_version}.tgz'),
        os.path.join(dst_dir, f'catboost-R-Windows-{release_version}.tgz')
    )

    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostr-darwin-universal2-{release_version}.dylib'),
        os.path.join(dst_dir, f'libcatboostr-darwin.dylib')
    )
    # copy with different suffix for compatibility
    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostr-darwin.dylib'),
        os.path.join(dst_dir, f'libcatboostr-darwin.so')
    )

    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostr-linux-x86_64-{release_version}.so'),
        os.path.join(dst_dir, f'libcatboostr-linux.so')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostr-windows-x86_64-{release_version}.dll'),
        os.path.join(dst_dir, f'libcatboostr.dll')
    )

def prepare_catboostmodel_lib(src_dir: str, dst_dir: str, release_version: str):
    for system, archs in get_sys_arch_list():
        lib_prefix = '' if system == 'windows' else 'lib'
        lib_suffixes = {
            'darwin': ['.dylib'],
            'linux': ['.so'],
            'windows': ['.lib', '.dll']
        }[system]

        for arch in archs:
            for lib_suffix in lib_suffixes:
                os.rename(
                    os.path.join(src_dir, f'model_interface_{system}-{arch}', f'{lib_prefix}catboostmodel{lib_suffix}'),
                    os.path.join(dst_dir, f'{lib_prefix}catboostmodel-{system}-{arch}-{release_version}{lib_suffix}')
                )

    # legacy names for compatibility
    for lib_suffix in ['.lib', '.dll']:
        shutil.copy2(
            os.path.join(dst_dir, f'catboostmodel-windows-x86_64-{release_version}{lib_suffix}'),
            os.path.join(dst_dir, f'catboostmodel{lib_suffix}')
        )
    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostmodel-darwin-universal2-{release_version}.dylib'),
        os.path.join(dst_dir, 'libcatboostmodel.dylib')
    )
    shutil.copy2(
        os.path.join(dst_dir, f'libcatboostmodel-linux-x86_64-{release_version}.so'),
        os.path.join(dst_dir, 'libcatboostmodel.so')
    )


def prepare_artifacts(src_dir: str, dst_dir: str, release_version: str):
    os.mkdir(dst_dir)

    with tempfile.TemporaryDirectory() as tmp_dir:
        prepare_app(src_dir, dst_dir, release_version)
        prepare_R_package(src_dir, dst_dir, release_version, tmp_dir)
        prepare_catboostmodel_lib(src_dir, dst_dir, release_version)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--src-dir', help='directory with fetched artifacts', default='./')
    parser.add_argument('--dst-dir', help='directory with artifacts ready for upload', default='./upload')
    parser.add_argument('--release-version', help='release version', required=True)
    parsed_args = parser.parse_args()

    prepare_artifacts(**vars(parsed_args))
