#Requires -Version 7.4
# Example Imperative Plugin - demonstrates direct vARC executor usage
#
# PATTERN: Imperative
# This plugin demonstrates the IMPERATIVE pattern - calling vARC executors directly
# from PowerShell code for maximum flexibility and control.
#
# USE THIS PATTERN WHEN:
# - Actions depend on results of previous actions
# - Complex branching or conditional logic is needed
# - You need custom error handling between actions
# - Actions have interdependencies that can't be expressed in TOML
# - You need to compute values dynamically at runtime
#
# KEY DIFFERENCES FROM DECLARATIVE:
# - No TOML template file
# - Direct calls to Invoke-vSEAL*Action executors
# - Manual baseline capture via Add-vSEALBaselineEntry
# - Full PowerShell control flow available

#region Plugin Contract

function Get-PluginConfigSchema {
    <#
    .SYNOPSIS
        Defines configuration options for this plugin.

    .DESCRIPTION
        Imperative plugins can still have config-driven behavior.
        The difference is the config is consumed by PowerShell logic,
        not by a TOML template.
    #>
    @{
        demo_mode = @{
            Type        = 'bool'
            Default     = $true
            Required    = $false
            Description = 'When true, logs extra detail about executor calls'
        }
        registry_prefix = @{
            Type        = 'string'
            Default     = 'HKLM:\SOFTWARE\vSEAL\Mock\Imperative'
            Required    = $false
            Description = 'Registry path prefix for mock settings'
        }
    }
}

function Test-Applicable {
    <#
    .SYNOPSIS
        Determines if this plugin should run on the current system.

    .DESCRIPTION
        For this mock/example plugin, we're always applicable.
        Real plugins would check for software presence, OS version, etc.
    #>
    param($Globals)

    # Example: could check globals for conditions
    # if ($Globals.OS.Build -lt 22000) {
    #     return @{ Applicable = $false; Reason = 'Requires Windows 11/Server 2022+' }
    # }

    return @{ Applicable = $true; Reason = $null }
}

function Get-PlannedActions {
    <#
    .SYNOPSIS
        Returns human-readable descriptions of planned actions.

    .DESCRIPTION
        This function is called during the planning/preview phase to show
        users what the plugin will do without actually executing.
    #>
    param($Config, $Globals, $Phase)

    $actions = @()

    if ($Phase -eq 'Seal') {
        $actions += 'Set registry values for custom configuration'
        $actions += 'Disable mock service (vSEALMockService)'
        $actions += 'Disable mock scheduled task (\vSEAL\Mock\ImperativeTask)'
        $actions += 'Execute mock configuration command'
    }
    elseif ($Phase -eq 'Engage') {
        $actions += 'Restore registry values to defaults'
        $actions += 'Enable mock service (vSEALMockService)'
        $actions += 'Enable mock scheduled task'
        $actions += 'Execute cleanup command'
    }

    return $actions
}

#endregion

#region Phase Implementation

function Invoke-Seal {
    <#
    .SYNOPSIS
        Executes the Seal phase with direct vARC executor calls.

    .DESCRIPTION
        This is the core demonstration of the IMPERATIVE pattern.

        KEY POINTS:
        1. Each executor call returns a result object with Status, Baseline, etc.
        2. After EACH successful action, call Add-vSEALBaselineEntry manually
        3. Check result.Status before proceeding or capturing baseline
        4. The PluginId is the folder name (e.g., 'example-imperative')

        EXECUTOR RETURN STRUCTURE:
        - Action:   The action type (e.g., 'registry.set', 'service.set')
        - Target:   What was modified (registry path, service name, etc.)
        - Status:   'Success', 'Failed', 'Skipped', or 'Timeout'
        - Message:  Error/info message if applicable
        - Baseline: Original state captured before modification
        - Duration: Milliseconds taken
    #>
    param($Config, $Globals)

    # The PluginId is used for baseline file naming: baselines/{timestamp}/example-imperative.json
    $pluginId = 'example-imperative'

    # Get config values with defaults
    $demoMode = $Config.demo_mode ?? $true
    $registryPrefix = $Config.registry_prefix ?? 'HKLM:\SOFTWARE\vSEAL\Mock\Imperative'

    Write-vSEALLog "Starting imperative seal with demo_mode=$demoMode"

    # =============================================================================
    # REGISTRY ACTIONS - Invoke-vSEALRegistryAction
    # =============================================================================
    # Registry executor supports three actions:
    #   - Set: Create or update a registry value
    #   - Delete: Remove a specific registry value
    #   - DeleteKey: Remove an entire registry key
    # =============================================================================

    Write-vSEALLog "Configuring mock registry settings..."

    # Example 1: Set a DWord value
    # This demonstrates the most common registry action pattern
    $regResult1 = Invoke-vSEALRegistryAction -Action Set `
        -Key "$registryPrefix" `
        -Name 'ConfigurationVersion' `
        -Data 42 `
        -Type DWord

    if ($demoMode) {
        Write-vSEALLog "Registry executor returned: Status=$($regResult1.Status), Duration=$($regResult1.Duration)ms" -Level DEBUG
    }

    # Capture baseline only on success - this is critical for rollback
    if ($regResult1.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Registry `
            -Target $regResult1.Target `
            -OriginalValue $regResult1.Baseline `
            -AppliedValue @{ Data = 42; Type = 'DWord' }
        Write-vSEALLog "Registry: $($regResult1.Target) = 42 (DWord)"
    }
    else {
        Write-vSEALLog "Registry action failed: $($regResult1.Message)" -Level WARNING
    }

    # Example 2: Set a String value - showing different type
    $regResult2 = Invoke-vSEALRegistryAction -Action Set `
        -Key "$registryPrefix" `
        -Name 'SealedBy' `
        -Data 'vSEAL Imperative Plugin' `
        -Type String

    if ($regResult2.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Registry `
            -Target $regResult2.Target `
            -OriginalValue $regResult2.Baseline `
            -AppliedValue @{ Data = 'vSEAL Imperative Plugin'; Type = 'String' }
        Write-vSEALLog "Registry: $($regResult2.Target) = 'vSEAL Imperative Plugin'"
    }

    # Example 3: Set a MultiString value - showing array data
    $multiStringData = @('Value1', 'Value2', 'Value3')
    $regResult3 = Invoke-vSEALRegistryAction -Action Set `
        -Key "$registryPrefix" `
        -Name 'FeatureFlags' `
        -Data $multiStringData `
        -Type MultiString

    if ($regResult3.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Registry `
            -Target $regResult3.Target `
            -OriginalValue $regResult3.Baseline `
            -AppliedValue @{ Data = $multiStringData; Type = 'MultiString' }
        Write-vSEALLog "Registry: $($regResult3.Target) set with MultiString"
    }

    # =============================================================================
    # SERVICE ACTIONS - Invoke-vSEALServiceAction
    # =============================================================================
    # Service executor changes start mode and optionally stops the service.
    # Parameters:
    #   -Name: Service name
    #   -StartMode: 'Automatic', 'Manual', or 'Disabled'
    #   -StopIfRunning: Switch, defaults to $true
    # Returns Skipped if service doesn't exist (common in mock scenarios)
    # =============================================================================

    Write-vSEALLog "Configuring mock service..."

    $svcResult = Invoke-vSEALServiceAction -Name 'vSEALMockService' -StartMode Disabled

    # Handle all possible statuses
    switch ($svcResult.Status) {
        'Success' {
            # Service existed and was modified - capture baseline
            Add-vSEALBaselineEntry -PluginId $pluginId `
                -Type Service `
                -Target $svcResult.Target `
                -OriginalValue $svcResult.Baseline `
                -AppliedValue @{ StartMode = 'Disabled' }
            Write-vSEALLog "Service '$($svcResult.Target)' disabled"
        }
        'Skipped' {
            # Service doesn't exist - expected for mock, log at DEBUG
            Write-vSEALLog "Service 'vSEALMockService' not found (expected in mock environment)" -Level DEBUG
        }
        'Failed' {
            # Actual error occurred
            Write-vSEALLog "Service action failed: $($svcResult.Message)" -Level WARNING
        }
    }

    # =============================================================================
    # TASK ACTIONS - Invoke-vSEALTaskAction
    # =============================================================================
    # Task executor enables or disables scheduled tasks.
    # Parameters:
    #   -Name: Full task path (e.g., 'Microsoft\Windows\Defrag\ScheduledDefrag')
    #   -Action: 'Enable' or 'Disable'
    # Note: Task paths use backslash separators, can include or omit leading backslash
    # Returns Skipped if task doesn't exist (common with mock tasks)
    # =============================================================================

    Write-vSEALLog "Disabling mock scheduled task..."

    $taskResult = Invoke-vSEALTaskAction -Name '\vSEAL\Mock\ImperativeTask' -Action Disable

    switch ($taskResult.Status) {
        'Success' {
            Add-vSEALBaselineEntry -PluginId $pluginId `
                -Type Task `
                -Target $taskResult.Target `
                -OriginalValue $taskResult.Baseline `
                -AppliedValue @{ State = 'Disabled' }
            Write-vSEALLog "Task '$($taskResult.Target)' disabled"
        }
        'Skipped' {
            # Task doesn't exist - expected for mock
            Write-vSEALLog "Task '\vSEAL\Mock\ImperativeTask' not found (expected in mock environment)" -Level DEBUG
        }
        'Failed' {
            Write-vSEALLog "Task action failed: $($taskResult.Message)" -Level WARNING
        }
    }

    # =============================================================================
    # COMMAND ACTIONS - Invoke-vSEALCommandAction
    # =============================================================================
    # Command executor runs shell commands with timeout enforcement.
    # Parameters:
    #   -Command: The command line to execute
    #   -Description: Human-readable description for logging
    #   -Timeout: Seconds (1-600, default 120)
    #   -SuccessExitCodes: Array of acceptable exit codes (default @(0, 3010))
    #   -RollbackCommand: Command to run during rollback (stored in baseline)
    # Returns:
    #   - ExitCode: The process exit code
    #   - RebootRequired: $true if exit code was 3010
    # =============================================================================

    Write-vSEALLog "Executing mock configuration command..."

    $cmdResult = Invoke-vSEALCommandAction `
        -Command 'echo "Mock imperative seal command executed successfully"' `
        -Description 'Apply mock configuration' `
        -Timeout 30 `
        -RollbackCommand 'echo "Mock imperative rollback command"'

    switch ($cmdResult.Status) {
        'Success' {
            # Command completed successfully
            Add-vSEALBaselineEntry -PluginId $pluginId `
                -Type Command `
                -Target $cmdResult.Target `
                -OriginalValue $cmdResult.Baseline `
                -AppliedValue @{
                    Command  = 'echo "Mock imperative seal command executed successfully"'
                    ExitCode = $cmdResult.ExitCode
                } `
                -Metadata @{
                    Duration = $cmdResult.Duration
                }
            Write-vSEALLog "Command completed: Exit code $($cmdResult.ExitCode)"

            # Check for reboot requirement (exit code 3010)
            if ($cmdResult.RebootRequired) {
                Write-vSEALLog "Note: Reboot required flag set" -Level WARNING
            }
        }
        'Timeout' {
            Write-vSEALLog "Command timed out after $($cmdResult.Duration)ms" -Level WARNING
        }
        'Failed' {
            Write-vSEALLog "Command failed: $($cmdResult.Message)" -Level WARNING
        }
    }

    # =============================================================================
    # CONDITIONAL LOGIC EXAMPLE
    # =============================================================================
    # The imperative pattern shines when you need conditional logic between actions.
    # Here's an example of making decisions based on previous results:
    # =============================================================================

    # Example: Only run additional registry action if first one succeeded
    if ($regResult1.Status -eq 'Success') {
        $regResult4 = Invoke-vSEALRegistryAction -Action Set `
            -Key "$registryPrefix" `
            -Name 'DependentSetting' `
            -Data 1 `
            -Type DWord

        if ($regResult4.Status -eq 'Success') {
            Add-vSEALBaselineEntry -PluginId $pluginId `
                -Type Registry `
                -Target $regResult4.Target `
                -OriginalValue $regResult4.Baseline `
                -AppliedValue @{ Data = 1; Type = 'DWord' }
            Write-vSEALLog "Dependent registry setting applied"
        }
    }
    else {
        Write-vSEALLog "Skipping dependent setting (prerequisite failed)" -Level DEBUG
    }

    Write-vSEALLog "Imperative seal phase complete"
}

function Invoke-Engage {
    <#
    .SYNOPSIS
        Executes the Engage phase - reverses Seal operations.

    .DESCRIPTION
        The Engage phase typically reverses what Seal did.
        In production, this might re-enable services, restore registry values, etc.

        Note: In a full vARC implementation, you would typically use
        Invoke-vSEALCoreRollback with baseline entries to automatically
        reverse changes. This example shows manual engage logic for
        demonstration purposes.
    #>
    param($Config, $Globals)

    $pluginId = 'example-imperative'
    $demoMode = $Config.demo_mode ?? $true
    $registryPrefix = $Config.registry_prefix ?? 'HKLM:\SOFTWARE\vSEAL\Mock\Imperative'

    Write-vSEALLog "Starting imperative engage phase..."

    # =============================================================================
    # ENGAGE: Reverse the Seal operations
    # =============================================================================

    # Re-enable mock service (will Skipped since it doesn't exist)
    $svcResult = Invoke-vSEALServiceAction -Name 'vSEALMockService' -StartMode Automatic

    if ($svcResult.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Service `
            -Target $svcResult.Target `
            -OriginalValue $svcResult.Baseline `
            -AppliedValue @{ StartMode = 'Automatic' }
        Write-vSEALLog "Service '$($svcResult.Target)' enabled (Automatic)"
    }
    elseif ($svcResult.Status -eq 'Skipped') {
        Write-vSEALLog "Service 'vSEALMockService' not found (expected)" -Level DEBUG
    }

    # Re-enable mock task
    $taskResult = Invoke-vSEALTaskAction -Name '\vSEAL\Mock\ImperativeTask' -Action Enable

    if ($taskResult.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Task `
            -Target $taskResult.Target `
            -OriginalValue $taskResult.Baseline `
            -AppliedValue @{ State = 'Ready' }
        Write-vSEALLog "Task '$($taskResult.Target)' enabled"
    }
    elseif ($taskResult.Status -eq 'Skipped') {
        Write-vSEALLog "Task not found (expected)" -Level DEBUG
    }

    # Delete the seal-time registry values (cleanup)
    $regResult1 = Invoke-vSEALRegistryAction -Action DeleteKey `
        -Key "$registryPrefix"

    if ($regResult1.Status -eq 'Success') {
        Add-vSEALBaselineEntry -PluginId $pluginId `
            -Type Registry `
            -Target "$registryPrefix" `
            -OriginalValue $regResult1.Baseline `
            -AppliedValue $null `
            -DidNotExist
        Write-vSEALLog "Registry key '$registryPrefix' deleted"
    }
    elseif ($regResult1.Status -eq 'Failed') {
        # Key might not exist if Seal didn't run
        if ($regResult1.Message -match 'not exist') {
            Write-vSEALLog "Registry key already clean" -Level DEBUG
        }
        else {
            Write-vSEALLog "Registry cleanup failed: $($regResult1.Message)" -Level WARNING
        }
    }

    # Run engage-time command
    $cmdResult = Invoke-vSEALCommandAction `
        -Command 'echo "Mock imperative engage completed"' `
        -Description 'Engage cleanup command' `
        -Timeout 30

    if ($cmdResult.Status -eq 'Success') {
        Write-vSEALLog "Engage command completed"
    }

    Write-vSEALLog "Imperative engage phase complete"
}

#endregion
