src/public/Orchestration/Resume-AitherOrchestration.ps1

#Requires -Version 7.0

<#
.SYNOPSIS
    Resume a failed or stopped orchestration execution

.DESCRIPTION
    Resumes a failed or stopped playbook execution from where it left off.
    Skips scripts that already completed successfully and continues with remaining scripts.
    Useful for recovering from temporary failures.

.PARAMETER PlaybookName
    Name of the playbook to resume. Resumes the most recent failed/stopped execution.

.PARAMETER ExecutionId
    Specific execution ID to resume.

.PARAMETER SkipFailed
    Skip scripts that failed previously and continue with remaining scripts.

.PARAMETER RetryFailed
    Retry scripts that failed previously instead of skipping them.

.INPUTS
    System.String
    You can pipe playbook names or execution IDs to Resume-AitherOrchestration.

.OUTPUTS
    PSCustomObject
    Returns resume result with Success, ExecutionId, and ResumedScripts properties.

.EXAMPLE
    Resume-AitherOrchestration -PlaybookName "deployment"

    Resumes the failed "deployment" playbook execution.

.EXAMPLE
    Resume-AitherOrchestration -ExecutionId "abc123" -RetryFailed

    Resumes a specific execution and retries failed scripts.

.NOTES
    Resuming orchestration will:
    - Load previous execution state
    - Skip completed scripts
    - Retry or skip failed scripts based on parameters
    - Continue with remaining scripts

.LINK
    Get-AitherOrchestrationStatus
    Invoke-AitherPlaybook
    Stop-AitherOrchestration
#>

function Resume-AitherOrchestration {
    [OutputType([PSCustomObject])]
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [string]$PlaybookName,

        [Parameter(ValueFromPipelineByPropertyName)]
        [string]$ExecutionId,

        [switch]$SkipFailed,

        [switch]$RetryFailed,

        [switch]$ShowOutput
    )

    begin {
        # Save original log targets
        $originalLogTargets = $script:AitherLogTargets

        # Set log targets based on ShowOutput parameter
        if ($ShowOutput) {
            # Ensure Console is in the log targets
            if ($script:AitherLogTargets -notcontains 'Console') {
                $script:AitherLogTargets += 'Console'
            }
        }
        else {
            # Remove Console from log targets if present (default behavior)
            if ($script:AitherLogTargets -contains 'Console') {
                $script:AitherLogTargets = $script:AitherLogTargets | Where-Object { $_ -ne 'Console' }
            }
        }
    }

    process {
        try {
            # During module validation, skip execution
            if ($PSCmdlet.MyInvocation.InvocationName -eq '.' -and -not $PlaybookName -and -not $ExecutionId) {
                return $null
            }

            # Check if Get-AitherOrchestrationStatus is available
            if (-not (Get-Command Get-AitherOrchestrationStatus -ErrorAction SilentlyContinue)) {
                Write-AitherLog -Level Warning -Message "Get-AitherOrchestrationStatus is not available. Cannot resume orchestration." -Source 'Resume-AitherOrchestration'
                return $null
            }

            # Get orchestration status
            $statusParams = @{}
            if ($PlaybookName) {
                $statusParams.PlaybookName = $PlaybookName
            }
            if ($ExecutionId) {
                $statusParams.ExecutionId = $ExecutionId
            }

            $status = Get-AitherOrchestrationStatus @statusParams | Select-Object -First 1

            if (-not $status) {
                throw "No orchestration found for: $PlaybookName"
            }
            if ($status.Status -eq 'Running') {
                Write-AitherLog -Level Warning -Message "Orchestration is already running. Cannot resume." -Source 'Resume-AitherOrchestration'
                return [PSCustomObject]@{
                    Success = $false
                    Message = "Orchestration is already running"
                }
            }

            if ($PSCmdlet.ShouldProcess($status.PlaybookName, "Resume orchestration execution")) {
                # Load playbook
                $playbook = Get-AitherPlaybook -Name $status.PlaybookName

                if (-not $playbook) {
                    throw "Playbook not found: $($status.PlaybookName)"
                }

                # Resume execution via orchestration engine
                $resumeParams = @{
                    LoadPlaybook    = $status.PlaybookName
                    ContinueOnError = $true
                }
                if ($RetryFailed) {
                    $resumeParams.RetryFailed = $true
                }
                elseif ($SkipFailed) {
                    $resumeParams.SkipFailed = $true
                }

                if (Get-Command Invoke-OrchestrationSequence -ErrorAction SilentlyContinue) {
                    $result = Invoke-OrchestrationSequence @resumeParams

                    Write-AitherLog -Level Information -Message "Resumed orchestration: $($status.PlaybookName)" -Source $PSCmdlet.MyInvocation.MyCommand.Name -Data @{
                        ExecutionId = $status.ExecutionId
                        RetryFailed = $RetryFailed
                        SkipFailed  = $SkipFailed
                    }
                    return [PSCustomObject]@{
                        Success        = $true
                        ExecutionId    = $status.ExecutionId
                        PlaybookName   = $status.PlaybookName
                        ResumedScripts = if ($result.Completed) { $result.Completed } else { 0 }
                    }
                }
                else {
                    throw "OrchestrationEngine not available"
                }
            }
        }
        catch {
            # Use centralized error handling
            $errorScript = Join-Path $PSScriptRoot '..' 'Private' 'Write-AitherError.ps1'
            if (Test-Path $errorScript) {
                . $errorScript -ErrorRecord $_ -CmdletName $PSCmdlet.MyInvocation.MyCommand.Name -Operation "Resuming orchestration: $PlaybookName" -Parameters $PSBoundParameters -ThrowOnError
            }
            else {
                $errorObject = [PSCustomObject]@{
                    PSTypeName = 'AitherZero.Error'
                    Success    = $false
                    ErrorId    = [System.Guid]::NewGuid().ToString()
                    Cmdlet     = $PSCmdlet.MyInvocation.MyCommand.Name
                    Operation  = "Resuming orchestration: $PlaybookName"
                    Error      = $_.Exception.Message
                    Timestamp  = Get-Date
                }
                Write-Output $errorObject

            Write-AitherLog -Level Error -Message "Failed to resume orchestration $PlaybookName : $($_.Exception.Message)" -Source $PSCmdlet.MyInvocation.MyCommand.Name -Exception $_
        }
        throw
    }
    finally {
        # Restore original log targets
        $script:AitherLogTargets = $originalLogTargets
    }
}}