#Requires -Version 7.4

function Test-vSEALPluginRequirements {
    <#
    .SYNOPSIS
        Evaluates plugin requirements against the current environment.

    .DESCRIPTION
        Checks if a plugin's requirements are satisfied by the current environment.
        Returns a Pass/Reason result indicating whether the plugin should be loaded.

        Requirements are evaluated in order of cost (cheapest first) with short-circuit
        on first failure. If no requirements are specified, the plugin is universal
        and loads everywhere.

    .PARAMETER Requires
        Hashtable containing plugin requirements from [plugin.requires] section.
        Expected keys: MinVsealVersion, MaxVsealVersion, MinBuild, MaxBuild,
        OsTypes, Platforms, Architectures.

    .PARAMETER PluginName
        Name of the plugin being evaluated (for logging/error messages).

    .PARAMETER Context
        Optional environment context hashtable. If not provided, calls
        Get-vSEALRequirementsContext to get current environment.

    .OUTPUTS
        [PSCustomObject] with properties:
        - Pass: [bool] True if all requirements met
        - Reason: [string] Human-readable skip reason (null if Pass is true)

    .EXAMPLE
        $requires = @{ MinVsealVersion = '2.0.0' }
        $result = Test-vSEALPluginRequirements -Requires $requires -PluginName 'defender'
        # Returns: Pass=false, Reason="requires vSEAL 2.0.0+, current is 0.1.11"

    .EXAMPLE
        # Universal plugin (no requirements)
        $requires = @{ MinBuild = 0; MaxBuild = 99999; OsTypes = @(); Platforms = @() }
        $result = Test-vSEALPluginRequirements -Requires $requires -PluginName 'bloatware'
        # Returns: Pass=true, Reason=$null

    .EXAMPLE
        # Using Import-vSEALPluginMetadata output
        $metadata = Import-vSEALPluginMetadata -Path './plugins/defender'
        $result = Test-vSEALPluginRequirements -Requires $metadata.Requires -PluginName $metadata.Name
        if (-not $result.Pass) {
            Write-Host "Skipping $($metadata.Name): $($result.Reason)"
        }

    .NOTES
        Evaluation order (cheapest first):
        1. min_vseal_version (SemVer comparison)
        2. max_vseal_version (SemVer comparison)
        3. min_build (integer comparison)
        4. max_build (integer comparison)
        5. architectures (OR logic)
        6. os_types (OR logic)
        7. platforms (OR logic)

    .LINK
        Get-vSEALRequirementsContext
        Import-vSEALPluginMetadata
    #>
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)]
        [hashtable]$Requires,

        [Parameter(Mandatory)]
        [string]$PluginName,

        [Parameter()]
        [hashtable]$Context
    )

    try {
        # Get context (use provided or fetch from cache)
        $ctx = $Context ?? (Get-vSEALRequirementsContext)

        # Universal plugin check: If no requirements specified, return Pass=true immediately
        $hasAnyRequirement = $Requires.MinVsealVersion -or $Requires.MaxVsealVersion -or
                             $Requires.MinBuild -gt 0 -or $Requires.MaxBuild -lt 99999 -or
                             ($Requires.OsTypes -and $Requires.OsTypes.Count -gt 0) -or
                             ($Requires.Platforms -and $Requires.Platforms.Count -gt 0) -or
                             ($Requires.Architectures -and $Requires.Architectures.Count -gt 0)

        if (-not $hasAnyRequirement) {
            Write-vSEALLog "Plugin '$PluginName' has no requirements (universal plugin)" -Level 'VERBOSE'
            return [PSCustomObject]@{ Pass = $true; Reason = $null }
        }

        # Evaluation order: cheapest first, short-circuit on failure

        # 1. min_vseal_version (SemVer comparison)
        if ($Requires.MinVsealVersion) {
            try {
                $minVersion = [System.Management.Automation.SemanticVersion]$Requires.MinVsealVersion
                $currentVersion = [System.Management.Automation.SemanticVersion]$ctx.vSEALVersion

                if ($currentVersion -lt $minVersion) {
                    $reason = "requires vSEAL $($Requires.MinVsealVersion)+, current is $($ctx.vSEALVersion)"
                    Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                    return [PSCustomObject]@{ Pass = $false; Reason = $reason }
                }
            }
            catch {
                $reason = "invalid min_vseal_version '$($Requires.MinVsealVersion)': $($_.Exception.Message)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'WARNING'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 2. max_vseal_version (SemVer comparison)
        if ($Requires.MaxVsealVersion) {
            try {
                $maxVersion = [System.Management.Automation.SemanticVersion]$Requires.MaxVsealVersion
                $currentVersion = [System.Management.Automation.SemanticVersion]$ctx.vSEALVersion

                if ($currentVersion -gt $maxVersion) {
                    $reason = "requires vSEAL $($Requires.MaxVsealVersion) or earlier, current is $($ctx.vSEALVersion)"
                    Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                    return [PSCustomObject]@{ Pass = $false; Reason = $reason }
                }
            }
            catch {
                $reason = "invalid max_vseal_version '$($Requires.MaxVsealVersion)': $($_.Exception.Message)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'WARNING'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 3. min_build (integer comparison)
        if ($Requires.MinBuild -and $Requires.MinBuild -gt 0) {
            if ([int]$ctx.Build -lt [int]$Requires.MinBuild) {
                $reason = "requires Windows build $($Requires.MinBuild)+, current is $($ctx.Build)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 4. max_build (integer comparison)
        if ($Requires.MaxBuild -and $Requires.MaxBuild -lt 99999) {
            if ([int]$ctx.Build -gt [int]$Requires.MaxBuild) {
                $reason = "requires Windows build $($Requires.MaxBuild) or earlier, current is $($ctx.Build)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 5. architectures (OR logic - any match passes)
        if ($Requires.Architectures -and $Requires.Architectures.Count -gt 0) {
            # Normalize to lowercase for comparison
            $allowedArchs = $Requires.Architectures | ForEach-Object { $_.ToLower() }
            if ($ctx.Architecture -notin $allowedArchs) {
                $archList = $allowedArchs -join '/'
                $reason = "requires $archList architecture, current is $($ctx.Architecture)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 6. os_types (OR logic - any match passes)
        if ($Requires.OsTypes -and $Requires.OsTypes.Count -gt 0) {
            # Normalize to lowercase for comparison
            $allowedTypes = $Requires.OsTypes | ForEach-Object { $_.ToLower() }
            if ($ctx.OsType -notin $allowedTypes) {
                $typeList = $allowedTypes -join '/'
                $reason = "requires $typeList OS, current is $($ctx.OsType)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # 7. platforms (OR logic - any match passes)
        if ($Requires.Platforms -and $Requires.Platforms.Count -gt 0) {
            # Normalize to lowercase for comparison
            $allowedPlatforms = $Requires.Platforms | ForEach-Object { $_.ToLower() }
            if ($ctx.Platform -notin $allowedPlatforms) {
                $platformList = $allowedPlatforms -join '/'
                $reason = "requires $platformList platform, current is $($ctx.Platform)"
                Write-vSEALLog "Plugin '$PluginName' skipped: $reason" -Level 'VERBOSE'
                return [PSCustomObject]@{ Pass = $false; Reason = $reason }
            }
        }

        # All requirements passed
        Write-vSEALLog "Plugin '$PluginName' requirements satisfied" -Level 'VERBOSE'
        return [PSCustomObject]@{ Pass = $true; Reason = $null }
    }
    catch {
        # Evaluation error - skip plugin with error reason
        $reason = "evaluation error: $($_.Exception.Message)"
        Write-vSEALLog "Plugin '$PluginName' requirements evaluation failed: $($_.Exception.Message)" -Level 'WARNING'
        return [PSCustomObject]@{ Pass = $false; Reason = $reason }
    }
}
