#!/usr/bin/env python3
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root
# of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#

import argparse
import functools
import json
import os
import pathlib
from pathlib import Path
import shutil
import subprocess
from tempfile import TemporaryDirectory

import sys
sys.path.append(str(Path(__file__).parent.parent.parent / 'Scripts'))
from builders.vcpkgbuilder import VcpkgBuilder
import builders.monkeypatch_tempdir_cleanup

class BlastBuilder(object):
    def __init__(self, workingDir: pathlib.Path, targetPlatform: str):
        self._workingDir = workingDir
        self._platform = targetPlatform
        self._env = dict(os.environ)
        self._env.update(
            PM_PACKAGES_ROOT=str(workingDir / 'packman-repo'),
        )

        self.check_call = functools.partial(subprocess.check_call,
            cwd=self.workingDir,
            env=self.env
        )

    @property
    def workingDir(self):
        return self._workingDir

    @property
    def platform(self):
        return self._platform

    @property
    def env(self):
        return self._env

    def clone(self, lockToCommit: str):
        if not (self.workingDir / '.git').exists():
            self.check_call(
                ['git', 'init',],
            )
            self.check_call(
                ['git', 'remote', 'add', 'origin', 'https://github.com/NVIDIAGameWorks/Blast.git',],
            )

        self.check_call(
            ['git', 'fetch', 'origin', '--depth=1', lockToCommit,],
        )
        self.check_call(
            ['git', 'checkout', lockToCommit,],
        )

    def build(self):
        cmake = str(self.workingDir / 'packman-repo/chk/cmake-x64/3.7.0/bin/cmake.exe') 
        self.check_call(
            ['cmd.exe', '/C', 'generate_projects_vc15win64.bat'],
        )

        for config in ('debug', 'profile', 'release'):
            self.check_call(
                [cmake, '--build', str(self.workingDir / 'compiler' / 'vc15win64-cmake'), '--config', config, '--', '/m:2']
            )

    def copyBuildOutputTo(self, packageDir: pathlib.Path):
        if packageDir.exists():
            shutil.rmtree(packageDir)

        def ignoreFilter(dirname, filenames):
            """
            Describes files that are generated by the Blast build that are excluded from the resulting package
            """
            # These filenames are always ignored
            staticIgnores = [
                'PhysXCommon_64.dll',
                'PhysXCooking_64.dll',
                'PhysXGpu_64.dll',
                'PhysX_64.dll',
                'ApexImporter_x64.exe',
                'ApexImporter_x64.ilk',
                'ApexImporter_x64.pdb',
                'AuthoringTool_x64.exe',
                'AuthoringTool_x64.ilk',
                'AuthoringTool_x64.pdb',
                'BlastPerfTests_x64.exe',
                'BlastPerfTests_x64.ilk',
                'BlastPerfTests_x64.pdb',
                'BlastUnitTests_x64.exe',
                'BlastUnitTests_x64.ilk',
                'BlastUnitTests_x64.pdb',
                'GFSDK_SSAO_D3D11.win64.dll',
                'GFSDK_ShadowLib_DX11.win64.dll',
                'LegacyConverter_x64.exe',
                'LegacyConverter_x64.ilk',
                'LegacyConverter_x64.pdb',
                'SampleAssetViewer_x64.exe',
                'SampleAssetViewer_x64.ilk',
                'SampleAssetViewer_x64.pdb',
                'd3dcompiler_47.dll',
                'nvToolsExt64_1.dll',
                'ApexImporter_x64.exp',
                'ApexImporter_x64.lib',
                'AuthoringTool_x64.exp',
                'AuthoringTool_x64.lib',
                'BlastPerfTests_x64.exp',
                'BlastPerfTests_x64.lib',
                'BlastUnitTests_x64.exp',
                'BlastUnitTests_x64.lib',
                'SampleAssetViewer_x64.exp',
                'SampleAssetViewer_x64.lib',
                'SampleBase_x64.lib',
                'SampleBase_x64.pdb',
            ]

            relDir = Path(dirname).relative_to(self.workingDir)
            # For files coming from the sdk/ and shared/ directories, we only want to copy the headers.
            # Path.is_relative_to needs Python 3.9 or newer
            if relDir.is_relative_to('sdk/') or relDir.is_relative_to('shared/'):
                # We want to keep all directories, so don't add directories to the ignore list
                # We only want to keep .h and .inl files
                # Ignore all others
                return [fn for fn in filenames if (path := Path(fn)) and ((not (self.workingDir/relDir/path).is_dir()) and (path.suffix not in ('.h', '.inl')))] \
                    + staticIgnores
            return staticIgnores

        for dirname in ('bin/vc15win64-cmake', 'lib/vc15win64-cmake', 'sdk', 'shared/utils'):
            shutil.copytree(
                src=self.workingDir / dirname,
                dst=packageDir / dirname,
                symlinks=True,
                ignore=ignoreFilter,
            )
        shutil.copy2(
            src=self.workingDir / 'license.txt',
            dst=packageDir / 'license.txt',
        )

    def writePackageInfoFile(self, packageDir: pathlib.Path, settings: dict):
        with (packageDir / 'PackageInfo.json').open('w') as fh:
            json.dump(settings, fh, indent=4)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--platform-name',
        dest='platformName',
        choices=['windows'],
        default=VcpkgBuilder.defaultPackagePlatformName(),
    )
    args = parser.parse_args()

    packageSystemDir = Path(__file__).resolve().parents[1]
    packageSourceDir = packageSystemDir / 'Blast'
    packageRoot = packageSystemDir / f'Blast-{args.platformName}'

    cmakeFindFile = packageSourceDir / f'FindBlast_{args.platformName}.cmake'
    if not cmakeFindFile.exists():
        cmakeFindFile = packageSourceDir / 'FindBlast.cmake'

    with TemporaryDirectory() as tempdir:
        tempdir = Path(tempdir)
        builder = BlastBuilder(workingDir=tempdir, targetPlatform=args.platformName)
        builder.clone('eb169fe87c9957d89e6132048317a5732299f6bf')
        builder.build()
        builder.copyBuildOutputTo(packageRoot/'Blast')

        # This version comes from running:
        # git clone https://github.com/NVIDIAGameWorks/Blast.git
        # git checkout eb169fe87c9957d89e6132048317a5732299f6bf
        # git describe
        # This yields v1.1.7_rc2-9-geb169fe, which describes commit eb169fe, which is 9 commits above the tag v1.1.7_rc2
        builder.writePackageInfoFile(
            packageRoot,
            settings={
                'PackageName': f'Blast-v1.1.7_rc2-9-geb169fe-rev2-{args.platformName}',
                'URL': 'https://github.com/NVIDIAGameWorks/Blast',
                'License': 'custom',
                'LicenseFile': 'Blast/license.txt',
            },
        )

        shutil.copy2(
            src=cmakeFindFile,
            dst=packageRoot / 'FindBlast.cmake'
        )

if __name__ == '__main__':
    main()
