###PREREQUISITES###
###Infrastructure to be deployed prior to running the script###
###Logged into azure on the subscription which the infrastructure was deployed###
[CmdletBinding(DefaultParameterSetName = 'Install')]

param(  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $false)]
    [string]  $webAppName,
  
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $true)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $false)]
    [string]  $resourceGroupName,

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

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

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

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

    [Parameter(ParameterSetName = 'Provision', Mandatory = $false)]
    [switch] $ProvisionFlag,

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

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


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

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

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

    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $storageAccountName,
    
    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $SQLServerName,
    
    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $location,
    
    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $TMAppServicePlan,
    
    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $storageAccountType,
    
    [Parameter(ParameterSetName = 'Install', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Update', Mandatory = $false)]
    [Parameter(ParameterSetName = 'Provision', Mandatory = $true)]
    [string]  $TMAppInsights

)

function Push-PackagesToWebApp {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $webAppName,
  
        [Parameter(Mandatory = $true)]
        [string]  $resourceGroupName,

        [Parameter(Mandatory = $true)]
        [string]  $pathToZip

    )
    az webapp deployment source config-zip --src $pathToZip `
        --name $webAppName `
        --resource-group $resourceGroupName
}
function Unify-Packages {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $pathToWebZip,
  
        [Parameter(Mandatory = $true)]
        [string]  $pathToCLIZip,

        [Parameter(Mandatory = $true)]
        [string]  $pathToDeploymentScriptZip,

        [Parameter(Mandatory = $true)]
        [string]  $pathToUnifiedZip,

        [Parameter(Mandatory = $false)]
        [string] $pathToBackUpAppSettingsFile
    )
    $unifiedFolder = $pathToUnifiedZip.Replace(".zip", "")
    If (!(Test-Path $unifiedFolder)) {
        New-Item -Path $unifiedFolder -ItemType Directory
    }
    Write-Output "Extracting and copying the web.zip..."
    $folder = Expand-Zip -pathToZip $pathToWebZip
    $pathToContent = $folder + "\Content\D_C\a\1\s\UiPath.TestManagementHub.WebAPI\obj\OnPremise\net6.0\PubTmp\Out\*"
    Copy-Item -Path $pathToContent -Destination $unifiedFolder -Recurse
    Remove-Item -Path $folder -Force -Recurse

    Write-Output "Extracting and copying the CLI..."
    $folder = Expand-Zip -pathToZip $pathToCLIZip
    $pathToContent = $folder + "\TestManagerProvisioner\*"
    $contentDestinationPath = $unifiedFolder + "\TestManagerProvisioner"
    $unifiedFolder = $pathToUnifiedZip.Replace(".zip", "")
    If (!(Test-Path $contentDestinationPath)) {
        New-Item -Path $contentDestinationPath -ItemType Directory
    }
    Copy-Item -Path $pathToContent -Destination $contentDestinationPath -Recurse
    Remove-Item -Path $folder -Force -Recurse

    Write-Output "Extracting and copying the Deploy Script..."
    $folder = Expand-Zip -pathToZip $pathToDeploymentScriptZip
    $pathToContent = $folder + "\Content\D_C\home\site\wwwroot\DeployScript\*"
    $contentDestinationPath = $unifiedFolder + "\DeployScript"
    If (!(Test-Path $contentDestinationPath)) {
        New-Item -Path $contentDestinationPath -ItemType Directory
    }
    Copy-Item -Path $pathToContent -Destination $contentDestinationPath -Recurse
    Remove-Item -Path $folder -Force -Recurse

    if (![string]::IsNullOrEmpty($pathToBackUpAppSettingsFile)) {
        $contentDestinationPath = $unifiedFolder + "\appsettings.json"
        Copy-Item -Path $pathToBackUpAppSettingsFile -Destination $contentDestinationPath -Force
        Remove-Item -Path $pathToBackUpAppSettingsFile
    }

    $compress = @{
        Path             = $unifiedFolder + "\*"
        CompressionLevel = "Fastest"
        DestinationPath  = $pathToUnifiedZip
    }
    
    Compress-Archive @compress
    Write-Output "Finished unifying archives."
    write-output "Cleaning up..."
    Remove-Item -Path $unifiedFolder -Force -Recurse
    Write-Output "Finished cleaning up."
    
}

function Expand-Zip {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $pathToZip
    )

    $folderPath = $pathToZip.Replace(".zip", "")
    Expand-Archive -LiteralPath $pathToZip -DestinationPath $folderPath
    return $folderPath
}
function Get-PublishProfile {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $webAppName,
  
        [Parameter(Mandatory = $true)]
        [string]  $resourceGroupName
    )
    $outputFilePath = ".\Temp\Profile.xml"
    $publishProfilesString = az webapp deployment list-publishing-profiles --resource-group $resourceGroupName --name $webAppName 
    $publishProfiles = $publishProfilesString | ConvertFrom-Json

    return $publishProfiles[0];
}

function Run-KuduCommand {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $userName,
  
        [Parameter(Mandatory = $true)]
        [string]  $password,

        [Parameter(Mandatory = $true)]
        [string]  $webAppName,

        [Parameter(Mandatory = $true)]
        [string]  $command,

        [Parameter(Mandatory = $true)]
        [string]  $dir
    )

    $body = @{
        "command" = $command
        "dir"     = $dir
    }

    $bytes = [System.Text.Encoding]::ASCII.GetBytes("$($userName):$($password)")
    $encodedCreds = [System.Convert]::ToBase64String($bytes)
    $headers = @{ Authorization = "Basic ${encodedCreds}" }
    $url = "https://$($webAppName).scm.azurewebsites.net/api/command"
    $result = Invoke-RestMethod -Method POST -ContentType "application/json" -Uri $Url -UseBasicParsing -Headers $headers -Body (ConvertTo-Json $body)

    return $result
}
function Download-AppSettingsFile {
    param (
        [Parameter(Mandatory = $true)]
        [string]  $userName,
  
        [Parameter(Mandatory = $true)]
        [string]  $password,

        [Parameter(Mandatory = $true)]
        [string]  $webAppName,

        [Parameter(Mandatory = $true)]
        [string]  $pathToBackUpAppSettingsFile)
    $url = "https://$webAppName.scm.azurewebsites.net/api/vfs/site/wwwroot/appsettings.json"
 
    # Encode username and password to base64 string  
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName, $password)))

    # pass the authentication to Header
    Invoke-WebRequest -Uri $url -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -Method GET -OutFile $pathToBackUpAppSettingsFile -ContentType "multipart/form-data"
}

function Main() {
    if ($ProvisionFlag -eq $false) {
        $pathToWebZip = ".\web.zip"
        $pathToCLIZip = ".\TestManagerProvisioner.zip"
        $pathToDeploymentScriptZip = ".\deploymentScript.zip"
        $pathToUnifiedZip = ".\unified.zip"
        $pathToTempAppSettingsFile = ".\appsettings.json"

        Write-Output "Getting publish profile..."
        $publishProfileContent = Get-PublishProfile -webAppName $webAppName -resourceGroupName $resourceGroupName
        $userName = $publishProfileContent.userName
        $password = $publishProfileContent.userPWD

        Write-Output "Unifying zips into a single zip file..."

        if ($UpdateFlag -eq $true) {
            Download-AppSettingsFile -pathToBackUpAppSettingsFile  $pathToTempAppSettingsFile `
            -userName $userName `
            -password $password `
            -webAppName $webAppName

            Unify-Packages -pathToWebZip $pathToWebZip `
                -pathToCLIZip $pathToCLIZip `
                -pathToDeploymentScriptZip $pathToDeploymentScriptZip `
                -pathToUnifiedZip $pathToUnifiedZip `
                -pathToBackUpAppSettingsFile $pathToTempAppSettingsFile
        }
        else {
            Unify-Packages -pathToWebZip $pathToWebZip `
                -pathToCLIZip $pathToCLIZip `
                -pathToDeploymentScriptZip $pathToDeploymentScriptZip `
                -pathToUnifiedZip $pathToUnifiedZip

        }
    
        Write-Output "Pushing zip file to Azure Web App..."
        Push-PackagesToWebApp `
            -webAppName $webAppName `
            -resourceGroupName $resourceGroupName `
            -pathToZip $pathToUnifiedZip 
   
        Remove-Item -Path $pathToUnifiedZip -Force
        
        $command = ""
        if ($UpdateFlag -eq $true) {
            $command = "powershell .\Deploy-TestManager.ps1 -UpdateFlag "
        }
        else {   
            $command = "powershell .\Deploy-TestManager.ps1 -identityUrl '{0}' -identityInstallationToken '{1}' -orchestratorUrl '{2}' -testManagerUrl '{3}' -dbConnectionString '{4}' -storageConnectionString '{5}' -appInsightsInstrKey '{6}' " `
                -f $identityUrl, $identityInstallationToken, $orchestratorUrl, $testManagerUrl, $dbConnectionString, $storageConnectionString, $appInsightsInstrKey
        }
        $dir = "site\\wwwroot\\DeployScript"

        Write-Output "Running install script on infrastructure..."
        $a = Run-KuduCommand -password $password `
            -userName $userName `
            -webAppName $webAppName `
            -command $command `
            -dir $dir 
        Write-Output $a.Error
    }
    else {
        $params=@{}
        $params.instalationType= @{"value"="Provision"}
        $params.instalationType= @{"testManagerVersion"="23.4.11"}
        $params.SQLServerAdminPassword= @{"value"=$SQLServerAdminPassword}
        $params.SQLServerAdminLogin= @{"value"=$SQLServerAdminLogin}
        $params.TMDBSize= @{"value"=$TMDBSize}
        $params.TMDatabaseName= @{"value"=$TMDatabaseName}
        $params.TMAppName= @{"value"=$TMAppName}
        $params.storageAccountName= @{"value"=$storageAccountName}
        $params.SQLServerName= @{"value"=$SQLServerName}
        $params.location= @{"value"=$location}
        $params.TMAppServicePlan= @{"value"=$TMAppServicePlan}
        $params.storageAccountType= @{"value"=$storageAccountType}
        $params.TMAppInsights= @{"value"=$TMAppInsights}
        $params.instalationType= @{"value"="Provision"}
        $params.identityUrl= @{"value"=""}
        $params.identityInstallationToken= @{"value"=""}
        $params.orchestratorUrl= @{"value"=""}
        #VALUES TO BE REPACED WITH PUBLIC STORAGE ACCOUNT URL AND SAS TOKEN
        $params._artifactsLocation= @{"value"="https://download.uipath.com/TestManagerAzureMarketplaceArtifacts/23.4.11/"}
        $params._artifactsLocationSasToken= @{"value"=""}

        $params | ConvertTo-Json -Depth 3 | Out-File ./arm/params.json

        az deployment group create --resource-group $resourceGroupName --template-file ./arm/mainTemplate.json --parameters ./arm/params.json
    }
}

Main
