from __future__ import unicode_literals

import contextlib
import sys
import os
import optparse
import json
import re
import subprocess

sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))

import find_depot_tools
from vs_toolchain import \
    SetEnvironmentAndGetRuntimeDllDirs, \
    SetEnvironmentAndGetSDKDir, \
    NormalizePath

sys.path.append("%s/win_toolchain" % find_depot_tools.add_depot_tools_to_path())

from get_toolchain_if_necessary import CalculateHash


@contextlib.contextmanager
def cwd(directory):
    curdir = os.getcwd()
    try:
        os.chdir(directory)
        yield
    finally:
        os.chdir(curdir)


def calculate_hash(root):
    with cwd(root):
        return CalculateHash('.', None)

def windows_installed_software():
    powershell_command = [
        "Get-CimInstance",
        "-Namespace",
        "root\cimv2",
        "-Class",
        "Win32_product",
        "|",
        "Select",
        "vendor,",
        "description,",
        "@{l='install_location';e='InstallLocation'},",
        "@{l='install_date';e='InstallDate'},",
        "@{l='install_date_2';e='InstallDate2'},",
        "caption,",
        "version,",
        "name,",
        "@{l='sku_number';e='SKUNumber'}",
        "|",
        "ConvertTo-Json",
    ]

    proc = subprocess.Popen(
        ["powershell.exe", "-Command", "-"],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
    )

    stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8"))

    if proc.returncode != 0:
        raise RuntimeError("Failed to get list of installed software")

    # On AppVeyor there's other output related to PSReadline,
    # so grab only the JSON output and ignore everything else
    json_match = re.match(
        r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL
    )

    if not json_match:
        raise RuntimeError(
            "Couldn't find JSON output for list of installed software"
        )

    # Filter out missing keys
    return list(
        map(
            lambda info: {k: info[k] for k in info if info[k]},
            json.loads(json_match.group(1)),
        )
    )


def windows_profile():
    runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
    win_sdk_dir = SetEnvironmentAndGetSDKDir()
    path = NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH'])

    # since current windows executable are symbols path dependant,
    # profile the current directory too
    return {
        'pwd': os.getcwd(),
        'installed_software': windows_installed_software(),
        'sdks': [
            {'name': 'vs', 'path': path, 'hash': calculate_hash(path)},
            {
                'name': 'wsdk',
                'path': win_sdk_dir,
                'hash': calculate_hash(win_sdk_dir),
            },
        ],
        'runtime_lib_dirs': runtime_dll_dirs,
    }


def main(options):
    if sys.platform == 'win32':
        with open(options.output_json, 'w') as f:
            json.dump(windows_profile(), f)
    else:
        raise OSError("Unsupported OS")


if __name__ == '__main__':
  parser = optparse.OptionParser()
  parser.add_option('--output-json', metavar='FILE', default='profile.json',
                    help='write information about toolchain to FILE')
  opts, args = parser.parse_args()
  sys.exit(main(opts))
