# cSpell:ignore PULLREQUEST
# cSpell:ignore TARGETBRANCH
[CmdletBinding()]
Param (
  [Parameter(Mandatory=$True)]
  [string] $ArtifactPath,
  [Parameter(Mandatory=$True)]
  [string] $PullRequestNumber,
  [Parameter(Mandatory=$True)]
  [string] $BuildId,
  [Parameter(Mandatory=$True)]
  [string] $CommitSha,
  [string] $APIViewUri,
  [string] $RepoFullName = "",
  [string] $ArtifactName = "packages",
  [string] $TargetBranch = ("origin/${env:SYSTEM_PULLREQUEST_TARGETBRANCH}" -replace "refs/heads/"),
  [string] $DevopsProject = "internal"
)

. (Join-Path $PSScriptRoot common.ps1)

$configFileDir = Join-Path -Path $ArtifactPath "PackageInfo"

# Submit API review request and return status whether current revision is approved or pending or failed to create review
function Submit-Request($filePath, $packageInfo)
{
    $packageName = $packageInfo.ArtifactName ?? $packageInfo.Name
    $packageType = $packageInfo.SdkType
    
    # Construct full package name with groupId if available
    $fullPackageName = $packageName
    if ($packageInfo.PSObject.Members.Name -contains "Group" -and $packageInfo.Group) {
        $fullPackageName = "$($packageInfo.Group):$packageName"
    }
    $repoName = $RepoFullName
    if (!$repoName) {
        $repoName = "azure/azure-sdk-for-$LanguageShort"
    }
    $reviewFileName = "$($packageName)_$($LanguageShort).json"
    $query = [System.Web.HttpUtility]::ParseQueryString('')
    $query.Add('artifactName', $ArtifactName)
    $query.Add('buildId', $BuildId)
    $query.Add('filePath', $filePath)
    $query.Add('commitSha', $CommitSha)
    $query.Add('repoName', $repoName)
    $query.Add('pullRequestNumber', $PullRequestNumber)
    $query.Add('packageName', $fullPackageName)
    $query.Add('language', $LanguageShort)
    $query.Add('project', $DevopsProject)
    $query.Add('packageType', $packageType)
    $reviewFileFullName = Join-Path -Path $ArtifactPath $packageName $reviewFileName
    # If CI generates token file then it passes both token file name and original file (filePath) to APIView
    # If both files are passed then APIView downloads the parent directory as a zip
    # If code file is not passed(for e.g. .NET or Java) then APIView needs full path to original file to download only that file.
    if (Test-Path $reviewFileFullName)
    {
        $query.Add('codeFile', $reviewFileName)
        # Pass only relative path in package artifact directory when code file is also present
        $query.Add('filePath', (Split-Path -Leaf $filePath))
    }
    else
    {
        $query.Add('filePath', $filePath)
    }
    $uri = [System.UriBuilder]$APIViewUri
    $uri.query = $query.toString()

    $correlationId = [System.Guid]::NewGuid().ToString()
    $headers = @{
      "x-correlation-id" = $correlationId
    }
    LogInfo "Request URI: $($uri.Uri.OriginalString)"
    LogInfo "Correlation ID: $correlationId"
    try
    {
        $Response = Invoke-WebRequest -Method 'GET' -Uri $uri.Uri -Headers $headers -MaximumRetryCount 3
        $StatusCode = $Response.StatusCode
        if ($Response.Headers['Content-Type'] -like 'application/json*') {
            $responseContent = $Response.Content | ConvertFrom-Json | ConvertTo-Json -Depth 10
            LogSuccess $responseContent
        }
    }
    catch
    {
        Write-Host "ERROR: API request failed" -ForegroundColor Red
        Write-Host "Status Code: $($_.Exception.Response.StatusCode.Value__)" -ForegroundColor Yellow
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow
        if ($_.ErrorDetails.Message) {
            Write-Host "Details: $($_.ErrorDetails.Message)" -ForegroundColor Yellow
        }
        LogError "Failed to detect API changes. See details above."
        $StatusCode = $_.Exception.Response.StatusCode
    }

    return $StatusCode
}

function Should-Process-Package($packageInfo)
{
    $packagePath = $packageInfo.DirectoryPath
    $modifiedFiles  = @(Get-ChangedFiles -DiffPath "$packagePath/*" -DiffFilterType '')
    $filteredFileCount = $modifiedFiles.Count
    LogInfo "Number of modified files for package: $filteredFileCount"
    return ($filteredFileCount -gt 0 -and $packageInfo.IsNewSdk)
}

function Log-Input-Params()
{
    LogGroupStart "Input Parameters for $($ArtifactName)"
    LogInfo "Artifact Path: $($ArtifactPath)"
    LogInfo "Artifact Name: $($ArtifactName)"
    LogInfo "PullRequest Number: $($PullRequestNumber)"
    LogInfo "BuildId: $($BuildId)"
    LogInfo "Language: $($Language)"
    LogInfo "Commit SHA: $($CommitSha)"
    LogInfo "Repo Name: $($RepoFullName)"
    LogInfo "Project: $($DevopsProject)"
    LogGroupEnd
}

Log-Input-Params

if (!($FindArtifactForApiReviewFn -and (Test-Path "Function:$FindArtifactForApiReviewFn")))
{
    LogError "The function for 'FindArtifactForApiReviewFn' was not found.`
    Make sure it is present in eng/scripts/Language-Settings.ps1 and referenced in eng/common/scripts/common.ps1.`
    See https://github.com/Azure/azure-sdk-tools/blob/main/doc/common/common_engsys.md#code-structure"
    exit 1
}

$responses = @{}

LogInfo "Processing PackageInfo at $configFileDir"

$packageInfoFiles = Get-ChildItem -Recurse -Force "$configFileDir" `
  | Where-Object {
      $_.Extension -eq '.json' -and ($_.FullName.Substring($configFileDir.Length + 1) -notmatch '^_.*?[\\\/]')
    }

foreach ($packageInfoFile in $packageInfoFiles)
{
    $packageInfo = Get-Content $packageInfoFile | ConvertFrom-Json
    $pkgArtifactName = $packageInfo.ArtifactName ?? $packageInfo.Name
    $packageType = $packageInfo.SdkType

    LogInfo "Processing $($pkgArtifactName)"

    # Check if the function supports the packageInfo parameter
    $functionInfo = Get-Command $FindArtifactForApiReviewFn -ErrorAction SilentlyContinue
    $supportsPackageInfoParam = $false

    if ($functionInfo -and $functionInfo.Parameters) {
        # Check if function specifically supports packageInfo parameter
        $parameterNames = $functionInfo.Parameters.Keys
        $supportsPackageInfoParam = $parameterNames -contains 'packageInfo'
    }

    # Call function with appropriate parameters
    if ($supportsPackageInfoParam) {
        LogInfo "Calling $FindArtifactForApiReviewFn with packageInfo parameter"
        $packages = &$FindArtifactForApiReviewFn $ArtifactPath $packageInfo
    }
    else {
        LogInfo "Calling $FindArtifactForApiReviewFn with legacy parameters"
        $packages = &$FindArtifactForApiReviewFn $ArtifactPath $pkgArtifactName
    }

    if ($packages)
    {
        $pkgPath = $packages.Values[0]
        $isRequired = Should-Process-Package $packageInfo
        LogInfo "Is API change detect required for $($pkgArtifactName):$($isRequired)"
        if ($isRequired -eq $True)
        {
            $filePath = $pkgPath.Replace($ArtifactPath , "").Replace("\", "/")
            $respCode = Submit-Request -filePath $filePath -packageInfo $packageInfo
            if ($respCode -ne '200')
            {
                $responses[$pkgArtifactName] = $respCode
            }
        }
        else
        {
            LogInfo "Pull request does not have any change for $($pkgArtifactName). Skipping API change detect."
        }
    }
    else
    {
        LogInfo "No package is found in artifact path to find API changes for $($pkgArtifactName)"
    }
}

foreach($pkg in $responses.keys)
{
    LogInfo "API detection request status for $($pkg) : $($responses[$pkg])"
}
