[CmdletBinding(DefaultParameterSetName = 'Install')]

param(  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $identityUrl,
  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $identityInstallationToken,
  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $orchestratorUrl,
  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $testManagerUrl,

    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $dbConnectionString,

    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $storageConnectionString,

    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [string]  $appInsightsInstrKey,

    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [switch] $UpdateFlag
)

$cliPath = 'D:\home\site\wwwroot\TestManagerProvisioner\testmanager.exe'
function Test-Prerequisites() {
    
    return Test-CLIPrerequisite
}
function Test-CLIPrerequisite() {
    
    if (Test-Path $cliPath -PathType Leaf) {
        return $true
    }
    return $false
}

function Run-TestManagerCLI($command, $params, $erroutput, $output) {
    $execArgs = "{0} {1}" -f $command, $params
    Write-Output $execArgs
    $process = Start-Process $cliPath -ArgumentList $execArgs -Wait -PassThru -RedirectStandardError $erroutput -RedirectStandardOutput $output
    if ($process.ExitCode -ne 0) {
        Write-Output "Exit code is $($process.ExitCode) when running cli with arguments: $execArgs"
        Write-Error "Command did not execute properly. Args: $execArgs"
        Exit 1
    }
}
function Configure-TestManager($appSettingsPath, $identityUrl, $identityInstallToken, $orchestratorUrl, $testManagerUrl, $dbConnectionString, $identityInstallationToken) {

    $installParams = '--appSettingsPath "{0}" --identityUrl "{1}" --identityInstallationToken "{2}" --orchestratorUrl "{3}" --testManagerUrl "{4}"' `
        -f $appSettingsPath, $identityUrl, $identityInstallToken, $orchestratorUrl, $testManagerUrl

    Write-Output 'Performing CLI install command.'
    Run-TestManagerCLI -command 'install' -params $installParams -erroutput 'D:\home\site\wwwroot\errInstall.txt' -output 'D:\home\site\wwwroot\outInstall.txt'

    Write-Output 'Performed CLI install command, Performing DB update command'
    $dbUpdateParams = '-cs "{0}"' -f $dbConnectionString
    Run-TestManagerCLI -command 'database update' -params $dbUpdateParams -erroutput 'D:\home\site\wwwroot\errDatabaseUpdate.txt' -output 'D:\home\site\wwwroot\outDatabaseUpdate.txt'

    Write-Output 'Performed CLI DB updated command, Performing CLI command feature sql-fulltext-search enable.'
    $featureUpdateParams = '-cs "{0}"' -f $dbConnectionString
    Run-TestManagerCLI -command 'feature sql-fulltext-search enable' -params  $featureUpdateParams -erroutput 'D:\home\site\wwwroot\errSqlFullTextSearchEnable.txt' -output 'D:\home\site\wwwroot\outSqlFullTextSearchEnable.txt'

    Write-Output 'Performed CLI command feature sql-fulltext-search enable. Enabling identity-resources-21-4 feature.'
    $featureS2SParams = '-asp "{0}" -iit "{1}" ' -f $appSettingsPath, $identityInstallationToken
    Run-TestManagerCLI -command 'feature identity-resources-21-4 enable' -params $featureS2SParams -erroutput 'D:\home\site\wwwroot\errIdentityResources21_4.txt' -output 'D:\home\site\wwwroot\outIdentityResources21_4.txt'

    Write-Output 'Performed CLI command feature identity-resources-21-4 enable.'
}
function Update-TestManager(){
    $appSettingsPath = 'D:\home\site\wwwroot\appsettings.json'
    $updateParams = '-asp "{0}"' -f $appSettingsPath
    Run-TestManagerCLI -command 'update' -params $updateParams -erroutput 'D:\home\site\wwwroot\errUpd.txt' -output 'D:\home\site\wwwroot\outUpd.txt'
}

function Deploy-TestManager($appSettingsPath, $identityUrl, $identityInstallationToken, $orchestratorUrl, $testManagerUrl, $dbConnectionString, $appInsightsInstrKey, $storageConnectionString) {
    try {
        $appSettingsPath = 'D:\home\site\wwwroot\appsettings.json'

        if (Test-Prerequisites) {
            Write-Output 'Starting writing configs to appSettings.json.'
            Update-AppSettings -dbConnectionString $dbConnectionString `
                -storageConnectionString $storageConnectionString `
                -appInsightsInstrKey $appInsightsInstrKey `
                -appSettingsPath $appSettingsPath
            Write-Output 'Finished writing configs to appSettings.json. Starting CLI calls.'

            Configure-TestManager -appSettingsPath $appSettingsPath `
                -identityUrl $identityUrl `
                -identityInstallToken $identityInstallationToken `
                -orchestratorUrl $orchestratorUrl `
                -testManagerUrl $testManagerUrl `
                -dbConnectionString $dbConnectionString `
                -identityInstallationToken $identityInstallationToken
            
        }
        else {
            throw "Prerequisites for installing Test Manager are not met. Aborting installation."
        }
    }
    catch {
        Write-Error $_
    }
    
}
function Read-File($filePath) {
    $object = Get-Content -Path $filePath | ConvertFrom-Json 
    return $object
}
function Write-File($filePath, $object) {
    $jsonObject = $object | ConvertTo-Json -Depth 10
    $jsonObject | Out-File -FilePath $filePath
}
function Construct-Object($keys, $currentKeyIndex, $value) {
    [int] $currentIndex = $currentKeyIndex
    if ($keys.Count - 1 -gt $currentIndex) {
        [int] $futureIndex = $currentIndex + 1 
        $newObj = Construct-Object -keys $keys -currentKeyIndex $futureIndex -value $value
        $returnObj = @{$keys[$currentIndex] = $newObj }
        return $returnObj
    }
    else {
        if ($currentIndex -gt $keys.Count - 1) {
            return $value
        }
        return @{$keys[$currentIndex] = $value }
    }
}
function Insert-PropertyInObject($object, $keys, $currentKeyIndex) {
    [int] $currentIndex = $currentKeyIndex
    $keyObject = $keys[$currentIndex]
    if ($object.$keyObject -ne $null) {
        $currentIndex++
        $obj = Insert-PropertyInObject -object $object.$keyObject -keys $keys -currentKeyIndex $currentIndex
        return $obj
    }
    else {
        [int]$futureIndex = $currentIndex + 1
        $memberObj = Construct-Object -keys $keys -currentKeyIndex $futureIndex -value $value
        $object |  Add-Member -MemberType NoteProperty -Name $keyObject -Value $memberObj
        return $object
    }
}
function Insert-KeyValueIntoAppSetting($key, $value, $appSettingsFilePath) {
    $segementedKey = $key.Split('__') | Where-Object { $_ -ne '' }
    $appSettings = Read-File -filePath $appSettingsFilePath 
    Insert-PropertyInObject -object $appSettings -keys $segementedKey -currentKeyIndex 0
    Write-File -filePath $appSettingsFilePath -object $appSettings
}

function Update-AppSettings($dbConnectionString, $storageConnectionString, $appInsightsInstrKey, $appSettingsPath) {
    Insert-KeyValueIntoAppSetting -key "NLog__targets__aiTarget__instrumentationKey" -value $appInsightsInstrKey -appSettingsFilePath $appSettingsPath
    Insert-KeyValueIntoAppSetting -key "Storage__Location" -value $storageConnectionString -appSettingsFilePath $appSettingsPath
    Insert-KeyValueIntoAppSetting -key "Storage__Provider" -value "AzureStorage" -appSettingsFilePath $appSettingsPath
    Insert-KeyValueIntoAppSetting -key "Database__ConnectionStrings__testmanagementhub" -value $dbConnectionString -appSettingsFilePath $appSettingsPath
}
  
function Main {
    Set-Location -Path "D:\home\site\wwwroot\TestManagerProvisioner"
    if ($UpdateFlag -eq $true) {
        Update-TestManager
    }
    else {
        Deploy-TestManager -identityUrl $identityUrl `
            -identityInstallationToken $identityInstallationToken `
            -orchestratorUrl $orchestratorUrl `
            -testManagerUrl $testManagerUrl `
            -dbConnectionString $dbConnectionString `
            -appInsightsInstrKey $appInsightsInstrKey `
            -storageConnectionString $storageConnectionString
    }
}

Main

if ($Error.Count -gt 0)
{
    Write-Output ("Exit due several errors: ")
    foreach ($err in $Error) {
        Write-Output ($err.Message)
    }
    Exit 1
}