Tests/Test-Win32AppLifecycle.ps1

# IntuneWin32App Module - Comprehensive Function Test Suite
# This script tests ALL public functions in the module through a complete lifecycle
# DO NOT RUN IN PRODUCTION - THESE ARE TEST SCRIPTS ONLY

# NOTE: This script has been replaced by Test-ComprehensiveFunctionality.ps1
# which provides complete testing of all 38 public functions.

Write-Host "=== DEPRECATED ===" -ForegroundColor Yellow
Write-Host "This test script has been replaced by Test-ComprehensiveFunctionality.ps1" -ForegroundColor Yellow
Write-Host "The new script tests ALL 38 public functions through a complete lifecycle workflow." -ForegroundColor Yellow
Write-Host ""
Write-Host "Running the new comprehensive test..." -ForegroundColor Cyan
Write-Host ""

# Run the new comprehensive test
$NewTestPath = Join-Path $PSScriptRoot "Test-ComprehensiveFunctionality.ps1"
if (Test-Path $NewTestPath) {
    & $NewTestPath
    exit $LASTEXITCODE
}
else {
    Write-Error "Test-ComprehensiveFunctionality.ps1 not found"
    exit 1
}

# Verify MSI files exist
if (Test-Path $TestConfig.SourceFolder) {
    $InitialMSI = Join-Path $TestConfig.SourceFolder $TestConfig.SetupFile
    $UpdatedMSI = Join-Path $TestConfig.SourceFolder $TestConfig.UpdatedSetupFile
    
    if (-not (Test-Path $InitialMSI)) {
        Write-Warning "Initial setup file not found: $($InitialMSI)"
    }
    if (-not (Test-Path $UpdatedMSI)) {
        Write-Warning "Updated setup file not found: $($UpdatedMSI)"
    }
    
    Write-Host "Using setup files:" -ForegroundColor Cyan
    Write-Host " Initial: $($TestConfig.SetupFile)" -ForegroundColor Gray
    Write-Host " Updated: $($TestConfig.UpdatedSetupFile)" -ForegroundColor Gray
}
else {
    Write-Warning "Source folder not found: $($TestConfig.SourceFolder)"
}

# Test Results Tracking
$TestResults = @{
    Passed = 0
    Failed = 0
    Details = @()
}

function Write-TestResult {
    param(
        [string]$TestName,
        [bool]$Passed,
        [string]$Details = ""
    )
    
    if ($Passed) {
        $TestResults.Passed++
        $Status = "PASSED"
        $Color = "Green"
    } else {
        $TestResults.Failed++
        $Status = "FAILED"
        $Color = "Red"
    }
    
    $Result = @{
        TestName = $TestName
        Status = $Status
        Details = $Details
        Timestamp = Get-Date
    }
    
    $TestResults.Details += $Result
    Write-Host "[$Status] $TestName" -ForegroundColor $Color
    if ($Details) {
        Write-Host " -> $Details" -ForegroundColor Gray
    }
}
#endregion

Write-Host "=== Win32 App Lifecycle Tests ===" -ForegroundColor Cyan
Write-Host "Testing: Package, Add, Update, Remove workflow" -ForegroundColor Yellow
Write-Host ""

#region Prerequisites
Write-Host "Checking prerequisites..." -ForegroundColor Yellow

# Module Import
try {
    # Remove module if already loaded to ensure fresh import
    if (Get-Module IntuneWin32App) {
        Remove-Module IntuneWin32App -Force
    }
    
    # Import from local path to ensure we get the latest changes
    $ModulePath = Split-Path $PSScriptRoot -Parent
    Import-Module (Join-Path $ModulePath "IntuneWin32App.psd1") -Force -Verbose:$false
    Write-TestResult -TestName "Module Import" -Passed $true
} catch {
    Write-TestResult -TestName "Module Import" -Passed $false -Details $_.Exception.Message
    exit 1
}

# File Prerequisites
$PrereqTests = @(
    @{ Path = $TestConfig.SourceFolder; Name = "Source Folder" }
)

# Test both setup files
$PrereqTests += @{ Path = Join-Path $TestConfig.SourceFolder $TestConfig.SetupFile; Name = "Initial Setup File" }
$PrereqTests += @{ Path = Join-Path $TestConfig.SourceFolder $TestConfig.UpdatedSetupFile; Name = "Updated Setup File" }

$PrereqTests += @{ Path = $TestConfig.OutputFolder; Name = "Output Folder" }

# Icon is optional - only test if path is configured
if ($TestConfig.IconPath) {
    $PrereqTests += @{ Path = $TestConfig.IconPath; Name = "Icon File" }
}

foreach ($PrereqTest in $PrereqTests) {
    if (Test-Path $PrereqTest.Path) {
        Write-TestResult -TestName "Prerequisite: $($PrereqTest.Name)" -Passed $true
    } else {
        Write-TestResult -TestName "Prerequisite: $($PrereqTest.Name)" -Passed $false -Details "Path not found: $($PrereqTest.Path)"
        exit 1
    }
}
#endregion

#region Authentication
Write-Host "\n=== Authentication ===" -ForegroundColor Cyan

try {
    Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Yellow
    $AuthResult = Connect-MSIntuneGraph -TenantID $TestConfig.TenantID -ClientID $TestConfig.ClientID -Interactive
    
    if ($AuthResult -and $Global:AuthenticationHeader) {
        Write-TestResult -TestName "Graph Authentication" -Passed $true -Details "Token acquired successfully"
        
        # Display token information for diagnostics
        if ($Global:AccessToken) {
            Write-Host "Token Scopes: $($Global:AccessToken.Scopes -join ', ')" -ForegroundColor Cyan
            Write-Host "Token Expires: $($Global:AccessToken.ExpiresOn)" -ForegroundColor Cyan
            
            # Store initial token for refresh testing
            $InitialAccessToken = $Global:AccessToken.AccessToken
            $InitialExpiresOn = $Global:AccessToken.ExpiresOn
            
            # Check if refresh token is available
            if ($Global:AccessToken.PSObject.Properties["RefreshToken"] -and -not [string]::IsNullOrEmpty($Global:AccessToken.RefreshToken)) {
                Write-Host "Refresh Token: Available (stored for silent renewal)" -ForegroundColor Cyan
                $RefreshTokenAvailable = $true
            }
            else {
                Write-Host "Refresh Token: Not available" -ForegroundColor Yellow
                $RefreshTokenAvailable = $false
            }
        }
        
        # Validate token
        $TokenValid = Test-AccessToken
        if ($TokenValid) {
            Write-TestResult -TestName "Access Token Validation" -Passed $true
            
            # Decode and display token claims for diagnostics
            try {
                Write-Host "`nDecoding Access Token..." -ForegroundColor Yellow
                $TokenParts = $Global:AccessToken.AccessToken.Split('.')
                $TokenPayload = $TokenParts[1]
                # Add padding if needed for Base64 decoding
                while ($TokenPayload.Length % 4) { $TokenPayload += '=' }
                $DecodedBytes = [System.Convert]::FromBase64String($TokenPayload)
                $DecodedToken = [System.Text.Encoding]::UTF8.GetString($DecodedBytes) | ConvertFrom-Json
                
                Write-Host "Token Claims:" -ForegroundColor Cyan
                Write-Host " User (upn): $($DecodedToken.upn)" -ForegroundColor Gray
                Write-Host " App ID (appid): $($DecodedToken.appid)" -ForegroundColor Gray
                Write-Host " Audience (aud): $($DecodedToken.aud)" -ForegroundColor Gray
                Write-Host " Issuer (iss): $($DecodedToken.iss)" -ForegroundColor Gray
                Write-Host " Scopes (scp): $($DecodedToken.scp)" -ForegroundColor Gray
                Write-Host " Roles: $($DecodedToken.roles -join ', ')" -ForegroundColor Gray
                Write-Host " Token Version (ver): $($DecodedToken.ver)" -ForegroundColor Gray
                Write-Host " Expires (exp): $(([System.DateTimeOffset]::FromUnixTimeSeconds($DecodedToken.exp)).LocalDateTime)" -ForegroundColor Gray
            }
            catch {
                Write-Warning "Failed to decode token: $_"
            }
            
            # Test token refresh if refresh token is available
            if ($RefreshTokenAvailable) {
                Write-Host "`nTesting Token Refresh..." -ForegroundColor Yellow
                try {
                    # Use -Refresh parameter to trigger silent token refresh
                    Write-Host "Attempting silent token refresh with -Refresh parameter..." -ForegroundColor Gray
                    $RefreshResult = Connect-MSIntuneGraph -TenantID $TestConfig.TenantID -ClientID $TestConfig.ClientID -Refresh
                    
                    if ($RefreshResult -and $Global:AccessToken.AccessToken -ne $InitialAccessToken) {
                        Write-TestResult -TestName "Token Refresh (Silent)" -Passed $true -Details "New token obtained via refresh token"
                        Write-Host " New Token Expires: $($Global:AccessToken.ExpiresOn)" -ForegroundColor Cyan
                        
                        # Validate the refreshed token
                        $RefreshedTokenValid = Test-AccessToken
                        if ($RefreshedTokenValid) {
                            Write-TestResult -TestName "Refreshed Token Validation" -Passed $true
                        }
                        else {
                            Write-TestResult -TestName "Refreshed Token Validation" -Passed $false -Details "Refreshed token is invalid"
                            exit 1
                        }
                    }
                    elseif ($RefreshResult -and $Global:AccessToken.AccessToken -eq $InitialAccessToken) {
                        Write-TestResult -TestName "Token Refresh (Silent)" -Passed $true -Details "Token still valid, refresh not needed"
                    }
                    else {
                        Write-TestResult -TestName "Token Refresh (Silent)" -Passed $false -Details "Refresh failed"
                    }
                }
                catch {
                    Write-TestResult -TestName "Token Refresh (Silent)" -Passed $false -Details $_.Exception.Message
                }
            }
            else {
                Write-Host "Skipping token refresh test - no refresh token available" -ForegroundColor Yellow
            }
        }
        else {
            Write-TestResult -TestName "Access Token Validation" -Passed $false -Details "Token is invalid or expired"
            exit 1
        }
    } else {
        Write-TestResult -TestName "Graph Authentication" -Passed $false -Details "Authentication failed - no token or header created"
        Write-Host "AuthResult: $($AuthResult -ne $null)" -ForegroundColor Yellow
        Write-Host "Global:AuthenticationHeader: $($Global:AuthenticationHeader -ne $null)" -ForegroundColor Yellow
        exit 1
    }
} catch {
    Write-TestResult -TestName "Graph Authentication" -Passed $false -Details $_.Exception.Message
    exit 1
}
#endregion

#region Phase 1: Package Creation
Write-Host "`n=== Phase 1: Package Creation ===" -ForegroundColor Cyan

try {
    Write-Host "Creating Win32 app package..." -ForegroundColor Yellow
    $PackageResult = New-IntuneWin32AppPackage -SourceFolder $TestConfig.SourceFolder -SetupFile $TestConfig.SetupFile -OutputFolder $TestConfig.OutputFolder -Force -InformationAction SilentlyContinue
    if ($PackageResult -and (Test-Path $PackageResult.Path)) {
        $TestConfig.PackagePath = $PackageResult.Path
        Write-TestResult -TestName "Package Creation" -Passed $true -Details "Package: $($PackageResult.Name)"
    } else {
        Write-TestResult -TestName "Package Creation" -Passed $false -Details "Package creation failed"
        exit 1
    }
} catch {
    Write-TestResult -TestName "Package Creation" -Passed $false -Details $_.Exception.Message
    exit 1
}

# Extract package metadata
try {
    $PackageMetadata = Get-IntuneWin32AppMetaData -FilePath $TestConfig.PackagePath
    if ($PackageMetadata) {
        Write-TestResult -TestName "Package Metadata Extraction" -Passed $true -Details "App: $($PackageMetadata.ApplicationInfo.Name)"
    } else {
        Write-TestResult -TestName "Package Metadata Extraction" -Passed $false
        exit 1
    }
} catch {
    Write-TestResult -TestName "Package Metadata Extraction" -Passed $false -Details $_.Exception.Message
    exit 1
}
#endregion

#region Phase 2: App Creation
Write-Host "`n=== Phase 2: App Creation ===" -ForegroundColor Cyan

# Verify token is still valid (automatic refresh should happen if needed)
Write-Host "Verifying token status before app creation..." -ForegroundColor Yellow
$TokenValid = Test-AccessToken
if ($TokenValid) {
    Write-Host "Token Status: Valid" -ForegroundColor Green
}
else {
    Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow
}

# Create app components
try {
    # Icon
    $Icon = New-IntuneWin32AppIcon -FilePath $TestConfig.IconPath
    Write-TestResult -TestName "Icon Creation" -Passed ($Icon -ne $null) -Details "Icon data prepared"
    
    # Detection Rule
    $DetectionRule = New-IntuneWin32AppDetectionRuleMSI -ProductCode $PackageMetadata.ApplicationInfo.MsiInfo.MsiProductCode -ProductVersionOperator "greaterThanOrEqual" -ProductVersion $PackageMetadata.ApplicationInfo.MsiInfo.MsiProductVersion
    Write-TestResult -TestName "Detection Rule Creation" -Passed ($DetectionRule -ne $null) -Details "MSI detection rule"
    
    # Requirement Rule (with ARM64 support)
    $RequirementRule = New-IntuneWin32AppRequirementRule -Architecture "AllWithARM64" -MinimumSupportedWindowsRelease "W10_22H2"
    Write-TestResult -TestName "Requirement Rule Creation" -Passed ($RequirementRule -ne $null) -Details "All architectures supported"
    
    # Return Code
    $ReturnCode = New-IntuneWin32AppReturnCode -ReturnCode 1337 -Type "retry"
    Write-TestResult -TestName "Return Code Creation" -Passed ($ReturnCode -ne $null) -Details "Custom return code: 1337"
    
} catch {
    Write-TestResult -TestName "App Components Creation" -Passed $false -Details $_.Exception.Message
    exit 1
}

# Test Graph API connectivity before creating app
try {
    Write-Host "Testing Graph API connectivity..." -ForegroundColor Yellow
    $TestQuery = Get-IntuneWin32App -DisplayName "NonExistentAppForTesting12345" -ErrorAction SilentlyContinue
    Write-TestResult -TestName "Graph API Connectivity" -Passed $true -Details "Successfully queried Graph API"
} catch {
    Write-TestResult -TestName "Graph API Connectivity" -Passed $false -Details $_.Exception.Message
    Write-Host "ERROR: Cannot connect to Graph API. Please verify:" -ForegroundColor Red
    Write-Host " 1. App registration has 'DeviceManagementApps.ReadWrite.All' permission" -ForegroundColor Yellow
    Write-Host " 2. Admin consent has been granted" -ForegroundColor Yellow
    Write-Host " 3. Token is not expired (check Test-AccessToken output above)" -ForegroundColor Yellow
    exit 1
}

# Create the app
try {
    Write-Host "Creating Win32 app in Intune..." -ForegroundColor Yellow
    $CreatedApp = Add-IntuneWin32App -FilePath $TestConfig.PackagePath -DisplayName $TestConfig.TestAppDisplayName -Description $TestConfig.TestAppDescription -Publisher $TestConfig.TestAppPublisher -AppVersion $TestConfig.TestAppVersion -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -RequirementRule $RequirementRule -Icon $Icon -ReturnCode $ReturnCode -Verbose
    
    if ($CreatedApp -and $CreatedApp.id) {
        $TestConfig.CreatedAppID = $CreatedApp.id
        Write-TestResult -TestName "App Creation" -Passed $true -Details "App ID: $($CreatedApp.id)"
    } else {
        Write-TestResult -TestName "App Creation" -Passed $false -Details "No app returned"
        exit 1
    }
} catch {
    Write-TestResult -TestName "App Creation" -Passed $false -Details $_.Exception.Message
    exit 1
}

# Verify app creation
try {
    Start-Sleep -Seconds 10  # Allow time for app to be processed
    $RetrievedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID
    if ($RetrievedApp -and $RetrievedApp.displayName -eq $TestConfig.TestAppDisplayName) {
        Write-TestResult -TestName "App Verification" -Passed $true -Details "App successfully created and retrieved"
    } else {
        Write-TestResult -TestName "App Verification" -Passed $false -Details "Could not retrieve created app"
    }
} catch {
    Write-TestResult -TestName "App Verification" -Passed $false -Details $_.Exception.Message
}
#endregion

#region Phase 3: App Update
Write-Host "`n=== Phase 3: App Update ===" -ForegroundColor Cyan

# Verify token is still valid (automatic refresh should happen if needed)
Write-Host "Verifying token status before app update..." -ForegroundColor Yellow
$TokenValid = Test-AccessToken
if ($TokenValid) {
    Write-Host "Token Status: Valid" -ForegroundColor Green
}
else {
    Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow
}

# Create updated package with different MSI file
try {
    Write-Host "Creating updated package with $($TestConfig.UpdatedSetupFile)..." -ForegroundColor Yellow
    $UpdatedPackageResult = New-IntuneWin32AppPackage -SourceFolder $TestConfig.SourceFolder -SetupFile $TestConfig.UpdatedSetupFile -OutputFolder $TestConfig.OutputFolder -Force -InformationAction SilentlyContinue
    if ($UpdatedPackageResult -and (Test-Path $UpdatedPackageResult.Path)) {
        $TestConfig.UpdatedPackagePath = $UpdatedPackageResult.Path
        Write-TestResult -TestName "Updated Package Creation" -Passed $true -Details "Updated package: $($TestConfig.UpdatedSetupFile)"
    } else {
        Write-TestResult -TestName "Updated Package Creation" -Passed $false -Details "Updated package creation failed"
    }
} catch {
    Write-TestResult -TestName "Updated Package Creation" -Passed $false -Details $_.Exception.Message
}

# Update app properties
if ($TestConfig.CreatedAppID) {
    try {
        Write-Host "Updating app properties..." -ForegroundColor Yellow
        
        # Update app metadata
        $UpdateResult = Set-IntuneWin32App -ID $TestConfig.CreatedAppID -AppVersion $TestConfig.UpdatedVersion -Description $TestConfig.UpdatedDescription -Verbose
        
        if ($UpdateResult -ne $null) {
            Write-TestResult -TestName "App Properties Update" -Passed $true -Details "Version and description updated"
            
            # Verify update
            Start-Sleep -Seconds 5
            $UpdatedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID
            if ($UpdatedApp.description -eq $TestConfig.UpdatedDescription) {
                Write-TestResult -TestName "App Update Verification" -Passed $true -Details "Updates applied successfully"
            } else {
                Write-TestResult -TestName "App Update Verification" -Passed $false -Details "Updates not reflected (Expected: '$($TestConfig.UpdatedDescription)', Got: '$($UpdatedApp.description)')"
            }
        } else {
            Write-TestResult -TestName "App Properties Update" -Passed $false -Details "Update operation returned null"
        }
    } catch {
        Write-TestResult -TestName "App Properties Update" -Passed $false -Details $_.Exception.Message
    }
}

# Update package content
if ($TestConfig.CreatedAppID -and $TestConfig.UpdatedPackagePath) {
    # Only attempt content update if we have a different package file
    if ($TestConfig.UpdatedPackagePath -ne $TestConfig.PackagePath) {
        try {
            Write-Host "Updating package content..." -ForegroundColor Yellow
            $ContentUpdateResult = Update-IntuneWin32AppPackageFile -ID $TestConfig.CreatedAppID -FilePath $TestConfig.UpdatedPackagePath -Verbose
            
            if ($ContentUpdateResult) {
                Write-TestResult -TestName "Package Content Update" -Passed $true -Details "Package content updated"
            } else {
                Write-TestResult -TestName "Package Content Update" -Passed $false -Details "Content update returned null"
            }
        } catch {
            Write-TestResult -TestName "Package Content Update" -Passed $false -Details $_.Exception.Message
        }
    } else {
        Write-TestResult -TestName "Package Content Update" -Passed $true -Details "Skipped - same package file (cannot update with identical content)"
    }
}
#endregion

#region Phase 4: Assignment Testing
Write-Host "`n=== Phase 4: Assignment Testing ===" -ForegroundColor Cyan

# Verify token is still valid (automatic refresh should happen if needed)
Write-Host "Verifying token status before assignment testing..." -ForegroundColor Yellow
$TokenValid = Test-AccessToken
if ($TokenValid) {
    Write-Host "Token Status: Valid" -ForegroundColor Green
}
else {
    Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow
}

if ($TestConfig.CreatedAppID) {
    # Test different assignment types
    try {
        # All Users - Available
        Write-Host "Creating All Users assignment..." -ForegroundColor Yellow
        $AllUsersAssignment = Add-IntuneWin32AppAssignmentAllUsers -ID $TestConfig.CreatedAppID -Intent "available" -Notification "showAll"
        Write-TestResult -TestName "All Users Assignment" -Passed ($AllUsersAssignment -ne $null) -Details "Available intent"
        
        Start-Sleep -Seconds 3
        
        # All Devices - Required
        Write-Host "Creating All Devices assignment..." -ForegroundColor Yellow
        $AllDevicesAssignment = Add-IntuneWin32AppAssignmentAllDevices -ID $TestConfig.CreatedAppID -Intent "required" -Notification "showReboot"
        Write-TestResult -TestName "All Devices Assignment" -Passed ($AllDevicesAssignment -ne $null) -Details "Required intent"
        
        # Wait for Graph API to propagate assignments
        Write-Host "Waiting for assignments to propagate in Graph API..." -ForegroundColor Yellow
        Start-Sleep -Seconds 10
        
        # Verify assignments with retry logic
        $MaxRetries = 3
        $RetryCount = 0
        $Assignments = $null
        
        while ($RetryCount -lt $MaxRetries) {
            $Assignments = Get-IntuneWin32AppAssignment -ID $TestConfig.CreatedAppID
            if ($Assignments -and $Assignments.Count -ge 2) {
                break
            }
            $RetryCount++
            if ($RetryCount -lt $MaxRetries) {
                Write-Host "Assignment count: $($Assignments.Count), retrying in 5 seconds... (Attempt $($RetryCount + 1)/$($MaxRetries))" -ForegroundColor Yellow
                Start-Sleep -Seconds 5
            }
        }
        
        Write-TestResult -TestName "Assignment Verification" -Passed ($Assignments.Count -ge 2) -Details "Found $($Assignments.Count) assignment(s) after $($RetryCount + 1) attempt(s)"
        
    } catch {
        Write-TestResult -TestName "Assignment Testing" -Passed $false -Details $_.Exception.Message
    }
}
#endregion

#region Phase 5: Cleanup (Removal)
Write-Host "`n=== Phase 5: Cleanup and Removal ===" -ForegroundColor Cyan

# Verify token is still valid (automatic refresh should happen if needed)
Write-Host "Verifying token status before cleanup..." -ForegroundColor Yellow
$TokenValid = Test-AccessToken
if ($TokenValid) {
    Write-Host "Token Status: Valid" -ForegroundColor Green
}
else {
    Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow
}

if ($TestConfig.CreatedAppID) {
    try {
        # Remove assignments first
        Write-Host "Removing assignments..." -ForegroundColor Yellow
        Remove-IntuneWin32AppAssignmentAllUsers -ID $TestConfig.CreatedAppID -Verbose
        Start-Sleep -Seconds 2
        Remove-IntuneWin32AppAssignmentAllDevices -ID $TestConfig.CreatedAppID -Verbose
        Write-TestResult -TestName "Assignment Removal" -Passed $true -Details "All assignments removed"
        
        Start-Sleep -Seconds 5
        
        # Remove the app
        Write-Host "Removing test app..." -ForegroundColor Yellow
        Remove-IntuneWin32App -ID $TestConfig.CreatedAppID -Verbose
        Write-TestResult -TestName "App Removal" -Passed $true -Details "App deletion initiated"
        
        # Verify removal
        Start-Sleep -Seconds 10
        try {
            $RemovedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID -ErrorAction Stop
            if ($RemovedApp -eq $null) {
                Write-TestResult -TestName "App Removal Verification" -Passed $true -Details "App successfully removed"
            } else {
                Write-TestResult -TestName "App Removal Verification" -Passed $false -Details "App still exists"
            }
        } catch {
            # If we get an error querying for the app, it likely means it was removed
            Write-TestResult -TestName "App Removal Verification" -Passed $true -Details "App successfully removed (not found in tenant)"
        }
        
    } catch {
        Write-TestResult -TestName "App Removal" -Passed $false -Details $_.Exception.Message
    }
}

# Clean up package files
$PackageFiles = @($TestConfig.PackagePath, $TestConfig.UpdatedPackagePath) | Where-Object { $_ -and (Test-Path $_) }
foreach ($PackageFile in $PackageFiles) {
    try {
        Remove-Item -Path $PackageFile -Force -ErrorAction Stop
        Write-TestResult -TestName "Package Cleanup" -Passed (-not(Test-Path $PackageFile)) -Details "Removed: $(Split-Path $PackageFile -Leaf)"
    } catch {
        Write-TestResult -TestName "Package Cleanup" -Passed $false -Details "Failed to remove: $(Split-Path $PackageFile -Leaf) - $($_.Exception.Message)"
    }
}
#endregion

#region Results Summary
Write-Host "`n=== Lifecycle Test Summary ===" -ForegroundColor Cyan
$TotalTests = $TestResults.Passed + $TestResults.Failed
$SuccessRate = if ($TotalTests -gt 0) { [math]::Round(($TestResults.Passed / $TotalTests) * 100, 2) } else { 0 }

Write-Host "Phases Completed:" -ForegroundColor White
Write-Host " [OK] Authentication with Token Refresh Support" -ForegroundColor Green
Write-Host " [OK] Package Creation and Metadata" -ForegroundColor Green
Write-Host " [OK] App Creation with Components" -ForegroundColor Green
Write-Host " [OK] App Updates (Properties and Content)" -ForegroundColor Green
Write-Host " [OK] Assignment Management" -ForegroundColor Green
Write-Host " [OK] Cleanup and Removal" -ForegroundColor Green

Write-Host ""
Write-Host "Test Results:" -ForegroundColor White
Write-Host " Passed: $($TestResults.Passed)" -ForegroundColor Green
Write-Host " Failed: $($TestResults.Failed)" -ForegroundColor Red
Write-Host " Success Rate: $SuccessRate%" -ForegroundColor $(
    if($SuccessRate -gt 90) { "Green" } 
    elseif($SuccessRate -gt 70) { "Yellow" } 
    else { "Red" }
)

# Export detailed results
$DetailedResults = @{
    TestSuite = "Win32 App Lifecycle"
    Summary = @{
        Passed = $TestResults.Passed
        Failed = $TestResults.Failed
        SuccessRate = $SuccessRate
        Timestamp = Get-Date
    }
    TestConfig = $TestConfig
    Details = $TestResults.Details
}

$ResultsPath = Join-Path $TestConfig.OutputFolder "Win32AppLifecycle_TestResults_$(Get-Date -Format "yyyyMMdd_HHmmss").json"
try {
    $DetailedResults | ConvertTo-Json -Depth 10 | Out-File -FilePath $ResultsPath -Encoding UTF8
    Write-Host "`nDetailed results: $ResultsPath" -ForegroundColor Cyan
} catch {
    Write-Warning "Could not export detailed results: $_"
}

if ($TestResults.Failed -gt 0) {
    Write-Host "`nFailed Tests:" -ForegroundColor Red
    $TestResults.Details | Where-Object { $_.Status -eq "FAILED" } | ForEach-Object {
        Write-Host " - $($_.TestName): $($_.Details)" -ForegroundColor Red
    }
    exit 1
} else {
    Write-Host "`n[SUCCESS] Complete lifecycle validation successful!" -ForegroundColor Green
    exit 0
}
#endregion