# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import re
import os
import subprocess

oldArguments = []
newArguments = []
allowedMissingArguments = {}
allowedMissingArguments['devops extension uninstall'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension install'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension enable'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension disable'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension show'] = ['--extension-name', '--publisher-name']

allowedNewMandatoryArguments = {}
allowedNewMandatoryArguments['devops extension uninstall'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension install'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension enable'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension disable'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension show'] = ['--extension-id', '--publisher-id']


# Do not compare these commands
ignoreCommands = []

class Arguments(dict):
    def __init__(self, command, name, isRequired):
        self.command = command
        self.name = name
        self.isRequired = isRequired
        dict.__init__(self,command = command, name = name, isRequired = isRequired)

def extractArgumentsFromCommand(command):
    print('running extractArgumentsFromCommand for ' + command)
    argumentList = []
    commandExtended = 'az ' + command + ' -h'
    help_text = subprocess.run(commandExtended.split(' '), shell=True, stdout=subprocess.PIPE)
    print('help text for ' + command)
    print(help_text)
    if " is in preview" in str(help_text):
        return argumentList
    regexReesult = re.search('Arguments(.*)Global Arguments',str(help_text))
    result = regexReesult.group(1)
    argumentLines = result.split('\\r\\n')

    for argumentLine in argumentLines:
        argumentLineSplits = argumentLine.split(" : ")
        if len(argumentLineSplits) > 1 and ' : ' in argumentLine:
            isRequired = False
            if '[Required]' in argumentLineSplits[0]:
                isRequired = True

            names = argumentLineSplits[0].replace('[Required]','').strip().split(' ')
            for name in names:
                argument = Arguments(command, name, isRequired)
                argumentList.append(argument)

    return argumentList

# remove azure-devops extension from index (if installed)
subprocess.run(['az', 'extension', 'remove', '-n', 'azure-devops'], shell=True)

# install extension from index
subprocess.run(['az', 'extension', 'add', '-n', 'azure-devops'], shell=True)

# Check the installed extensions
subprocess.run(['az', 'extension', 'list'], shell=True)

# add extension path to sys.path so that we can get all the commands
import sys
from azure.cli.core.extension import get_extension_path
# Make sure that the extension install directory is on sys.path so that dependencies can be found.
extensionPath = get_extension_path('azure-devops')
sys.path.append(extensionPath)

# loading commands from code
from azure.cli.core.mock import DummyCli
from azext_devops import DevCommandsLoader
cli_ctx = DummyCli()
loader = DevCommandsLoader(cli_ctx)
loader.load_command_table(None)

for command in loader.command_table:
    oldArguments.extend(extractArgumentsFromCommand(command))

print('Unload extension (loaded from index).')

# uninstall extension loaded from index
subprocess.run(['az', 'extension', 'remove', '-n', 'azure-devops'], shell=True, stdout=subprocess.PIPE)

# search and install extension from given path
def findExtension():
    for p, d, f in os.walk('.'):
        for file in f:
            if file.endswith('.whl'):
                return os.path.join(p, file)


newExtensionLocation = findExtension()
print('Install extension (loaded from current code). Wheel path - {}'.format(newExtensionLocation))
subprocess.run(['az', 'extension', 'add', '--source', newExtensionLocation, '-y'], shell=True, stdout=subprocess.PIPE)

# Check the installed extensions
subprocess.run(['az', 'extension', 'list'], shell=True)

# get a set of old commands, we are not reusing the set from ext because we want to keep this clean
oldCommands = []
for oldArgument in oldArguments:
    if oldArgument.command not in ignoreCommands:
        if not (oldArgument.command in oldCommands):
            oldCommands.append(oldArgument.command)
    else:
        print('Ignoring command.. ' + oldArgument.command)


# prepare argument set from new extension
for oldCommand in oldCommands:
    print("Running extract for command: {}".format(oldCommand))
    newArguments.extend(extractArgumentsFromCommand(oldCommand))

errorList = []

# make sure no new argument is mandatory
for newArgument in newArguments:
    if newArgument.isRequired is True:
        isNewMandatory = True
        for oldArgument in oldArguments:
            if oldArgument.command == newArgument.command and oldArgument.name == newArgument.name and oldArgument.isRequired is True:
                isNewMandatory = False
                break

        if isNewMandatory is True:
            allowedNewMandatoryArgumentsForCommand = allowedNewMandatoryArguments.get(newArgument.command, [])
            if not newArgument.name in allowedNewMandatoryArgumentsForCommand:
                errorList.append('\n' + 'New Mandatory argument found for command ' + newArgument.command + ' argument ' +  newArgument.name)

# make sure no argument is removed
for oldArgument in oldArguments:
    if oldArgument.command not in ignoreCommands:
        isArgumentMissing = True
        for newArgument in newArguments:
            if oldArgument.name == newArgument.name and oldArgument.command == newArgument.command:
                isArgumentMissing = False
                break

        if isArgumentMissing is True:
            allowedMissingArgumetsForCommand = allowedMissingArguments.get(oldArgument.command, [])
            if not oldArgument.name in allowedMissingArgumetsForCommand:
                errorList.append('\n' + 'Argument missing for command ' + oldArgument.command + ' argument ' +  oldArgument.name)

if len(errorList) > 0:
    import sys
    sys.stderr.write(' '.join(errorList))
    raise Exception('Something is not correct')
