---
parameters:
  - name: serviceConnection
    type: string
  - name: whatIfEnabled
    type: boolean
    default: true
  - name: scriptFiles
    type: object
    default:
      - displayName: "Example Deployment"
        templateFilePath: "./infra-as-code/bicep/modules/example/example.bicep"
        templateParametersFilePath: "./config/custom-parameters/example.parameters.all.json"
        managementGroupId: "00000000-0000-0000-0000-000000000000"
        subscriptionId: "00000000-0000-0000-0000-000000000000"
        resourceGroupName: "example-rg"
        location: "uksouth"
        deploymentType: "subscription"  # tenant | managementGroup | subscription | resourceGroup
        firstRunWhatIf: true
        runStep: true

steps:
  - task: AzurePowerShell@5
    displayName: Check for First Deployment
    condition: eq($${{ parameters.whatIfEnabled }}, true)
    inputs:
      azureSubscription: $${{ parameters.serviceConnection }}
      pwsh: true
      azurePowerShellVersion: LatestVersion
      ScriptType: "InlineScript"
      Inline: |
        $managementGroupId = $env:MANAGEMENT_GROUP_ID
        $managementGroups = Get-AzManagementGroup
        $managementGroup = $managementGroups | Where-Object { $_.Name -eq $managementGroupId }

        $firstDeployment = $true

        if($managementGroup -eq $null) {
          Write-Warning "Cannot find the $managementGroupId Management Group, so assuming this is the first deployment. We must skip checking some deployments since their dependent resources do not exist yet."
        } else {
          Write-Host "Found the $managementGroupId Management Group, so assuming this is not the first deployment."
          $firstDeployment = $false
        }

        Write-Host "##vso[task.setvariable variable=FIRST_DEPLOYMENT;]$firstDeployment"

  - $${{ each scriptFile in parameters.scriptFiles }}:
      - task: AzurePowerShell@5
        displayName: $${{ scriptFile.displayName }}
        condition: and(succeeded(), eq($${{ scriptFile.runStep }}, true))
        inputs:
          azureSubscription: $${{ parameters.serviceConnection }}
          pwsh: true
          azurePowerShellVersion: LatestVersion
          ScriptType: "InlineScript"
          Inline: |
            $whatIf = [System.Convert]::ToBoolean("$${{ parameters.whatIfEnabled }}")

            $firstDeploymentString = $env:FIRST_DEPLOYMENT
            $firstDeployment = $true
            if($firstDeploymentString -eq "") {
              $firstDeployment = $false
            } else {
              $firstDeployment = [System.Convert]::ToBoolean($firstDeploymentString)
            }

            $firstRunWhatIf = [System.Convert]::ToBoolean("$${{ scriptFile.firstRunWhatIf }}")

            if($whatIf -and $firstDeployment -and !$firstRunWhatIf) {
              Write-Warning "Skipping the WhatIf check as the deployment is dependent on resources that do not exist yet..."
              exit 0
            }

            $deploymentType = "$${{ scriptFile.deploymentType }}"

            $deploymentPrefix = $env:PREFIX
            $deploymentName = "$${{ scriptFile.displayName }}".Replace(" ", "-")
            $deploymentTimeStamp = Get-Date -Format 'yyyyMMddHHmmss'

            $prefixPostFixAndHythenLength = $deploymentPrefix.Length + $deploymentTimeStamp.Length + 2
            $deploymentNameMaxLength = 61 - $prefixPostFixAndHythenLength

            if($deploymentName.Length -gt $deploymentNameMaxLength) {
              $deploymentName = $deploymentName.Substring(0, $deploymentNameMaxLength)
            }

            $deploymentName = "$deploymentPrefix-$deploymentName-$deploymentTimeStamp"
            Write-Host "Deployment Name: $deploymentName"

            $inputObject = @{
              TemplateFile          = "$${{ scriptFile.templateFilePath }}"
              TemplateParameterFile = "$${{ scriptFile.templateParametersFilePath }}"
              WhatIf                = $whatIf
              Verbose               = $true
            }

            $retryCount = 0
            $retryMax = 10
            $initialRetryDelay = 20
            $retryDelayIncrement = 10
            $finalSuccess = $false

            while ($retryCount -lt $retryMax) {
              $retryAttempt = '{0:d2}' -f ($retryCount + 1)

              if($retryCount -gt 0) {
                $retryDelay = $initialRetryDelay + ($retryCount * $retryDelayIncrement)
                Write-Host "Retrying deployment with attempt number $retryAttempt after $retryDelay seconds..." -ForegroundColor Green
                Start-Sleep -Seconds $retryDelay
                Write-Host "Retrying deployment..." -ForegroundColor Green
              }

              $inputObject.DeploymentName = "$deploymentName-$retryAttempt"

              $result = $null

              try {
                if ($deploymentType -eq "tenant") {
                  $inputObject.Location = "$${{ scriptFile.location }}"
                  $result = New-AzTenantDeployment @inputObject
                }

                if ($deploymentType -eq "managementGroup") {
                  $inputObject.Location = "$${{ scriptFile.location }}"
                  $inputObject.ManagementGroupId = "$${{ scriptFile.managementGroupId }}"
                  if ($inputObject.ManagementGroupId -eq "") {
                    $inputObject.ManagementGroupId = (Get-AzContext).Tenant.TenantId
                  }
                  $result = New-AzManagementGroupDeployment @inputObject
                }

                if ($deploymentType -eq "subscription") {
                  $inputObject.Location = "$${{ scriptFile.location }}"
                  Select-AzSubscription -SubscriptionId "$${{ scriptFile.subscriptionId }}"
                  $result = New-AzSubscriptionDeployment @inputObject
                }

                if ($deploymentType -eq "resourceGroup") {
                  $inputObject.ResourceGroupName = "$${{ scriptFile.resourceGroupName }}"
                  Select-AzSubscription -SubscriptionId "$${{ scriptFile.subscriptionId }}"
                  $result = New-AzResourceGroupDeployment @inputObject
                }
              } catch {
                Write-Host $_ -ForegroundColor Red
                Write-Host "Deployment failed with exception, this is likely an intermittent failure so entering retry loop..." -ForegroundColor Red
                $retryCount++
                continue
              }

              if ($whatIf) {
                $result | Format-List | Out-Host
                exit 0
              }

              $resultId = ""

              if($deploymentType -eq "resourceGroup") {
                $resultId = "/subscriptions/$${{ scriptFile.subscriptionId }}/resourceGroups/$${{ scriptFile.resourceGroupName }}/providers/Microsoft.Resources/deployments/$deploymentName"
              } else {
                $resultId = $result.Id
              }

              $resultIdEscaped = $resultId.Replace("/", "%2F")
              $resultUrl = "https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/$resultIdEscaped"

              Write-Host "Deployment Name: $deploymentName"
              Write-Host "Deployment ID: $resultId"
              Write-Host "Deployment Url: $resultUrl"
              $result | Format-List | Out-Host

              if($result.ProvisioningState -ne "Succeeded") {
                Write-Host "Deployment failed with unsuccessful provisioning state, this is likely an intermittent failure so entering retry loop..." -ForegroundColor Red
                $retryCount++
              } else {
                $finalSuccess = $true
                break
              }
            }

            if($finalSuccess -eq $false) {
              Write-Error "Deployment failed after $retryMax attempts..."
              exit 1
            }
