#Requires -Version 7.4

function Invoke-vSEALCoreRollback {
    <#
    .SYNOPSIS
        Restores system state from baseline entries for declarative plugins.

    .DESCRIPTION
        Processes baseline entries in reverse order (LIFO) to restore each
        modified resource to its original state. This function is used for
        declarative plugins that don't have custom Invoke-Rollback functions.

        The function follows best-effort semantics: if one rollback fails,
        it continues with remaining entries and reports all failures at the end.

        Command actions without RollbackCommand are skipped with a verbose message.

    .PARAMETER Entries
        Array of baseline entries from Get-vSEALBaseline's Plugins property.
        Each entry should have Type, Target, and OriginalValue properties.

    .PARAMETER PluginId
        Plugin identifier for logging purposes (e.g., "defender").

    .OUTPUTS
        [PSCustomObject] Rollback result with properties:
        - Total: Total entry count
        - Restored: Successfully restored count
        - Failed: Failed rollback count
        - Skipped: Skipped entries (commands without rollback)
        - Errors: Array of error messages

    .EXAMPLE
        $baseline = Get-vSEALBaseline -Id '20260126_120000'
        $entries = $baseline.Plugins['defender']
        Invoke-vSEALCoreRollback -Entries $entries -PluginId 'defender'

        Rolls back all entries for the defender plugin.

    .NOTES
        Part of vARC (vSEAL Action Rollback Core) infrastructure.
        Plan 03 of Phase 22 (Orchestrator Integration).
    #>
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)]
        [AllowEmptyCollection()]
        [array]$Entries,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$PluginId
    )

    $result = @{
        Total         = $Entries.Count
        Restored      = 0
        Failed        = 0
        Skipped       = 0
        CustomSkipped = 0
        CustomEntries = @()
        Errors        = @()
    }

    if ($Entries.Count -eq 0) {
        Write-vSEALLog "No entries to rollback for $PluginId" -Level VERBOSE
        return [PSCustomObject]$result
    }

    # Process in reverse order (LIFO - last in, first out)
    $reversed = @($Entries)
    [array]::Reverse($reversed)

    Write-vSEALLog "Rolling back $($reversed.Count) entries for $PluginId" -Level VERBOSE

    foreach ($entry in $reversed) {
        $entryType = $entry.Type
        $entryTarget = $entry.Target
        $originalValue = $entry.OriginalValue

        try {
            switch ($entryType) {
                'Registry' {
                    Invoke-RegistryEntryRollback -Entry $entry
                    $result.Restored++
                    Write-vSEALLog "Restored registry: $entryTarget" -Level VERBOSE
                }
                'Service' {
                    Invoke-ServiceEntryRollback -Entry $entry
                    $result.Restored++
                    Write-vSEALLog "Restored service: $entryTarget" -Level VERBOSE
                }
                'Task' {
                    Invoke-TaskEntryRollback -Entry $entry
                    $result.Restored++
                    Write-vSEALLog "Restored task: $entryTarget" -Level VERBOSE
                }
                'Command' {
                    $rollbackCmd = $originalValue.RollbackCommand

                    if ([string]::IsNullOrEmpty($rollbackCmd)) {
                        Write-vSEALLog "Skipping command rollback (no rollback command): $entryTarget" -Level VERBOSE
                        $result.Skipped++
                    }
                    else {
                        $null = Invoke-vSEALCommandAction -Command $rollbackCmd -Description "Rollback: $entryTarget"
                        $result.Restored++
                        Write-vSEALLog "Rolled back command: $entryTarget" -Level VERBOSE
                    }
                }
                'Custom' {
                    $result.CustomSkipped++
                    $result.CustomEntries += $entryTarget
                }
                default {
                    Write-vSEALLog "Unknown entry type for rollback: $entryType" -Level WARNING
                    $result.Skipped++
                }
            }
        }
        catch {
            # Log error but continue with other entries (best effort)
            $errorMsg = "Rollback failed for $entryTarget : $($_.Exception.Message)"
            Write-vSEALLog $errorMsg -Level ERROR
            $result.Errors += $errorMsg
            $result.Failed++
        }
    }

    return [PSCustomObject]$result
}

# ===== PRIVATE ROLLBACK HELPERS =====

function Invoke-RegistryEntryRollback {
    <#
    .SYNOPSIS
        Rolls back a registry entry from baseline.
    #>
    param([Parameter(Mandatory)]$Entry)

    $target = $Entry.Target
    $originalValue = $Entry.OriginalValue

    # Parse target: "HKLM:\path\to\key\ValueName"
    $parts = $target -split '\\'
    $valueName = $parts[-1]
    $keyPath = ($parts[0..($parts.Count - 2)]) -join '\'

    if ($originalValue.DidNotExist -eq $true) {
        # Value didn't exist before - delete it
        $null = Invoke-vSEALRegistryAction -Action Delete -Key $keyPath -Name $valueName
    }
    else {
        # Restore original value
        if ($null -ne $originalValue.Data) {
            $null = Invoke-vSEALRegistryAction -Action Set -Key $keyPath -Name $valueName `
                -Data $originalValue.Data -Type ($originalValue.Type ?? 'String')
        }
    }
}

function Invoke-ServiceEntryRollback {
    <#
    .SYNOPSIS
        Rolls back a service entry from baseline.
    #>
    param([Parameter(Mandatory)]$Entry)

    $target = $Entry.Target
    $originalStartMode = $Entry.OriginalValue.StartMode

    if ([string]::IsNullOrEmpty($originalStartMode)) {
        throw "No original StartMode in baseline for service: $target"
    }

    $null = Invoke-vSEALServiceAction -Name $target -StartMode $originalStartMode
}

function Invoke-TaskEntryRollback {
    <#
    .SYNOPSIS
        Rolls back a task entry from baseline.
    #>
    param([Parameter(Mandatory)]$Entry)

    $target = $Entry.Target
    $originalState = $Entry.OriginalValue.State

    if ([string]::IsNullOrEmpty($originalState)) {
        throw "No original State in baseline for task: $target"
    }

    # Restore original state
    $restoreAction = if ($originalState -eq 'Disabled') { 'Disable' } else { 'Enable' }
    $null = Invoke-vSEALTaskAction -Name $target -Action $restoreAction
}
