[CmdLetBinding()]
Param(
    [Parameter(Mandatory = $true)] 
    [int]$RerunPassesRequiredToAvoidFailure,

    [string]$AccessToken = $env:SYSTEM_ACCESSTOKEN,
    [string]$CollectionUri = $env:SYSTEM_COLLECTIONURI,
    [string]$TeamProject = $env:SYSTEM_TEAMPROJECT,
    [string]$BuildUri = $env:BUILD_BUILDURI
)

. "$PSScriptRoot/AzurePipelinesHelperScripts.ps1"


$azureDevOpsRestApiHeaders = @{
    "Accept"="application/json"
    "Authorization"="Basic $([System.Convert]::ToBase64String([System.Text.ASCIIEncoding]::ASCII.GetBytes(":$AccessToken")))"
}

$queryUri = GetQueryTestRunsUri -CollectionUri $CollectionUri -TeamProject $TeamProject -BuildUri $BuildUri
Write-Host "queryUri = $queryUri"

# To account for unreliable tests, we'll iterate through all of the tests associated with this build, check to see any tests that were unreliable
# (denoted by being marked as "skipped"), and if so, we'll instead mark those tests with a warning and enumerate all of the attempted runs
# with their pass/fail states as well as any relevant error messages for failed attempts.
$testRuns = Invoke-RestMethodWithRetries $queryUri -Headers $azureDevOpsRestApiHeaders

$timesSeenByRunName = @{}
      
foreach ($testRun in $testRuns.value)
{
    $testRunResultsUri = "$($testRun.url)/results?api-version=5.0"
        
    Write-Host "Marking test run `"$($testRun.name)`" as in progress so we can change its results to account for unreliable tests."
    Invoke-RestMethod "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "InProgress" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null

    Write-Host "Retrieving test results..."
    $testResults = Invoke-RestMethodWithRetries $testRunResultsUri -Headers $azureDevOpsRestApiHeaders
        
    foreach ($testResult in $testResults.value)
    {
        $testNeedsSubResultProcessing = $false
        if ($testResult.outcome -eq "NotExecuted")
        {
            $testNeedsSubResultProcessing = $true
        }
        elseif($testResult.outcome -eq "Failed")
        {
            $testNeedsSubResultProcessing = $testResult.errorMessage -like "*_subresults.json*"
        }

        if ($testNeedsSubResultProcessing)
        {
            Write-Host "  Test $($testResult.testCaseTitle) was detected as unreliable. Updating..."
            
            # The errorMessage field contains a link to the JSON-encoded rerun result data.
            $resultsJson = Download-StringWithRetries "Error results" $testResult.errorMessage
            $rerunResults = ConvertFrom-Json $resultsJson
            [System.Collections.Generic.List[System.Collections.Hashtable]]$rerunDataList = @()
            $attemptCount = 0
            $passCount = 0
            $totalDuration = 0
            
            foreach ($rerun in $rerunResults.results)
            {
                $rerunData = @{
                    "displayName" = "Attempt #$($attemptCount + 1) - $($testResult.testCaseTitle)";
                    "durationInMs" = $rerun.duration;
                    "outcome" = $rerun.outcome;
                }

                if ($rerun.outcome -eq "Passed")
                {
                    $passCount++
                }
                
                if ($attemptCount -gt 0)
                {
                    $rerunData["sequenceId"] = $attemptCount
                }

                Write-Host "    Attempt #$($attemptCount + 1): $($rerun.outcome)"
                
                if ($rerun.outcome -ne "Passed")
                {
                    $screenshots = "$($rerunResults.blobPrefix)/$($rerun.screenshots -join @"
$($rerunResults.blobSuffix)
$($rerunResults.blobPrefix)
"@)$($rerunResults.blobSuffix)"

                    # We subtract 1 from the error index because we added 1 so we could use 0
                    # as a default value not injected into the JSON in order to keep its size down.
                    # We did this because there's a maximum size enforced for the errorMessage parameter
                    # in the Azure DevOps REST API.
                    $fullErrorMessage = @"
Log: $($rerunResults.blobPrefix)/$($rerun.log)$($rerunResults.blobSuffix)

Screenshots:
$screenshots

Error log:
$($rerunResults.errors[$rerun.errorIndex - 1])
"@

                    $rerunData["errorMessage"] = $fullErrorMessage
                }
                
                $attemptCount++
                $totalDuration += $rerun.duration
                $rerunDataList.Add($rerunData)
            }

            $overallOutcome = "Warning"
            
            if ($attemptCount -eq 2)
            {
                Write-Host "  Test $($testResult.testCaseTitle) passed on the immediate rerun, so we'll mark it as unreliable."
            }
            elseif ($passCount -gt $RerunPassesRequiredToAvoidFailure)
            {
                Write-Host "  Test $($testResult.testCaseTitle) passed on $passCount of $attemptCount attempts, which is greater than or equal to the $RerunPassesRequiredToAvoidFailure passes required to avoid being marked as failed. Marking as unreliable."
            }
            else
            {
                Write-Host "  Test $($testResult.testCaseTitle) passed on only $passCount of $attemptCount attempts, which is less than the $RerunPassesRequiredToAvoidFailure passes required to avoid being marked as failed. Marking as failed."
                $overallOutcome = "Failed"
            }
            
            $updateBody = ConvertTo-Json @(@{ "id" = $testResult.id; "outcome" = $overallOutcome; "errorMessage" = " "; "durationInMs" = $totalDuration; "subResults" = $rerunDataList; "resultGroupType" = "rerun" }) -Depth 5
            Invoke-RestMethod -Uri $testRunResultsUri -Method Patch -Headers $azureDevOpsRestApiHeaders -Body $updateBody -ContentType "application/json" | Out-Null
        }
    }
        
    Write-Host "Finished updates. Re-marking test run `"$($testRun.name)`" as completed."
    Invoke-RestMethod -Uri "$($testRun.url)?api-version=5.0" -Method Patch -Body (ConvertTo-Json @{ "state" = "Completed" }) -Headers $azureDevOpsRestApiHeaders -ContentType "application/json" | Out-Null
}
