#Requires -Version 7.4
# =============================================================================
# Declarative Plugin Example
# =============================================================================
#
# This file is a STUB for the declarative plugin pattern. The actual plugin
# logic is defined in the adjacent TOML file (declarative.toml).
#
# WHY A STUB IS NEEDED:
# ---------------------
# The vSEAL plugin discovery system scans for plugin.ps1 files in plugin folders.
# Even though all our actions are defined in TOML, we need this stub to:
#   1. Satisfy the plugin discovery requirement (must have plugin.ps1)
#   2. Provide the required plugin contract functions
#   3. Wire up the TOML template to the vARC execution engine
#
# THE DECLARATIVE PATTERN:
# ------------------------
# In a declarative plugin:
#   - The TOML file defines WHAT actions to perform
#   - The stub PowerShell defines HOW to load and execute those actions
#   - No custom logic beyond template loading
#   - All action types, conditions, and error handling are in TOML
#
# WHEN TO USE THIS PATTERN:
# -------------------------
# Use declarative plugins when:
#   - Actions are standard (registry, service, task, command)
#   - Conditions are straightforward (OS version, service/task/registry existence)
#   - No custom logic is needed during execution
#   - You want non-developers to maintain the configuration
#
# ALTERNATIVES:
# -------------
# - Hybrid pattern: TOML for actions + custom PowerShell for Analyze/Rollback
# - Imperative pattern: Full PowerShell with direct vARC executor calls
#
# =============================================================================

#region Plugin Contract Functions

function Get-PluginConfigSchema {
    <#
    .SYNOPSIS
        Returns the configuration schema for this plugin.

    .DESCRIPTION
        Declarative plugins typically have no additional configuration beyond
        what's in the TOML template. The template IS the configuration.

        If you needed user-configurable options (e.g., which groups to enable),
        you would define them here and access them via $Config in phase functions.

    .EXAMPLE
        # To add configurable options:
        @{
            enabled_groups = @{
                Type        = 'string[]'
                Default     = @('*')
                Required    = $false
                Description = 'Groups to execute (supports wildcards)'
            }
        }
    #>
    @{
        # Empty schema - all logic is in the TOML template
        # The template's metadata, groups, and conditions are self-contained
    }
}

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

    .DESCRIPTION
        Mock plugins are always applicable - they target non-existent resources
        and are safe to run on any system for testing/demonstration.

        In a production plugin, you would check:
        - Whether the software/service being configured exists
        - Whether the OS version is supported
        - Whether prerequisites are met

    .PARAMETER Globals
        Hashtable containing OS and Platform information:
        - $Globals.OS.Build, $Globals.OS.Name, $Globals.OS.IsServer
        - $Globals.Platform.Architecture
    #>
    param(
        [Parameter(Mandatory)]
        [hashtable]$Globals
    )

    # Mock plugin is always applicable - it's for testing/learning
    # In production, you might check:
    # if ($Globals.OS.Build -lt 22000) {
    #     return @{ Applicable = $false; Reason = 'Requires Windows 11 or Server 2022+' }
    # }

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

function Get-PlannedActions {
    <#
    .SYNOPSIS
        Returns human-readable descriptions of actions this plugin will perform.

    .DESCRIPTION
        This function is called during the planning phase to show users what
        will happen before execution. For declarative plugins, we extract
        the group descriptions from the TOML template.

    .PARAMETER Config
        Plugin configuration from TOML file (usually empty for declarative).

    .PARAMETER Globals
        OS and Platform information hashtable.

    .PARAMETER Phase
        The phase being planned: Seal or Engage.

    .OUTPUTS
        Array of strings describing planned actions.
    #>
    param(
        [Parameter()]
        [hashtable]$Config,

        [Parameter()]
        [hashtable]$Globals,

        [Parameter()]
        [ValidateSet('Seal', 'Engage')]
        [string]$Phase
    )

    # Load the template to extract group descriptions
    $templatePath = Join-Path $script:PluginScriptRoot 'declarative.toml'

    if (-not (Test-Path $templatePath)) {
        return @("Template file not found: $templatePath")
    }

    try {
        $template = Import-vSEALTemplate -Path $templatePath

        # Build action list from template groups
        $actions = @()

        foreach ($group in $template.Groups) {
            $groupName = $group.name ?? 'Unnamed group'
            $actionCount = $group.actions.Count

            # Add group summary
            $actions += "[Group: $groupName] $actionCount action(s)"

            # Optionally list individual actions (useful for verbose output)
            # foreach ($action in $group.actions) {
            #     $actions += "  - $($action.type): $($action.key ?? $action.name ?? $action.command)"
            # }
        }

        if ($actions.Count -eq 0) {
            $actions = @("No actions defined in template for $Phase phase")
        }

        return $actions
    }
    catch {
        return @("Failed to parse template: $_")
    }
}

#endregion

#region Phase Functions

function Invoke-Seal {
    <#
    .SYNOPSIS
        Executes the Seal phase by loading and processing the TOML template.

    .DESCRIPTION
        This is the core of the declarative pattern. Instead of writing
        PowerShell code for each action, we:

        1. Load the TOML template using Import-vSEALTemplate
        2. Iterate through each group defined in the template
        3. Pass each group to Invoke-vSEALActionGroup for execution
        4. The group processor handles:
           - Condition evaluation (group and per-action)
           - Action dispatch to appropriate executors
           - Baseline capture for rollback
           - Error handling (continue/stop/rollback strategies)

    .PARAMETER Config
        Plugin configuration from TOML file.

    .PARAMETER Globals
        OS and Platform information for condition evaluation.

    .NOTES
        ABOUT PLUGINID:
        The PluginId is the plugin folder name (e.g., "example-declarative").
        This ID is used for:
        - Baseline file naming (example-declarative.json)
        - Log context identification
        - Rollback targeting

        ABOUT GLOBALS:
        The Globals hashtable is passed through to the group processor so that
        globals-type conditions can evaluate OS version, architecture, etc.
    #>
    param(
        [Parameter()]
        [hashtable]$Config,

        [Parameter()]
        [hashtable]$Globals
    )

    # Resolve path to adjacent TOML template
    # The template MUST be in the same folder as this stub with matching name
    $templatePath = Join-Path $script:PluginScriptRoot 'declarative.toml'

    Write-vSEALLog -Message "Loading declarative template: $templatePath" -Level VERBOSE

    # Load and validate the template
    # Import-vSEALTemplate will throw on:
    # - File not found
    # - Invalid TOML syntax
    # - Missing required metadata
    # - Invalid action/condition definitions
    $template = Import-vSEALTemplate -Path $templatePath

    Write-vSEALLog -Message "Template '$($template.Metadata.Name)' loaded with $($template.Groups.Count) groups" -Level INFO

    # Process each group in the template
    # Groups are processed in order as defined in the TOML file
    foreach ($group in $template.Groups) {
        # Invoke-vSEALActionGroup is the vARC group processor
        # It handles:
        # - Group-level condition evaluation (all conditions must pass, AND logic)
        # - Per-action condition evaluation
        # - Dispatching actions to type-specific executors
        # - Baseline capture for successful actions
        # - Error handling strategies (continue/stop/rollback)
        $result = Invoke-vSEALActionGroup `
            -Group $group `
            -Phase 'Seal' `
            -PluginId 'example-declarative' `
            -Globals $Globals

        # Log the group result summary
        # Status can be: Completed, CompletedWithErrors, Stopped, RolledBack, Skipped
        $statusMsg = switch ($result.Status) {
            'Completed'           { "$($result.Succeeded)/$($result.Total) succeeded" }
            'CompletedWithErrors' { "$($result.Succeeded)/$($result.Total) succeeded, $($result.Failed) failed" }
            'Skipped'             { "skipped (conditions not met)" }
            'Stopped'             { "stopped at '$($result.StoppedBy)'" }
            'RolledBack'          { "rolled back ($($result.Failed) failures)" }
            default               { $result.Status }
        }

        Write-vSEALLog -Message "Group '$($result.Group)': $statusMsg" -Level INFO
    }

    Write-vSEALLog -Message "Declarative template execution complete" -Level VERBOSE
}

function Invoke-Engage {
    <#
    .SYNOPSIS
        Executes the Engage phase by loading and processing the TOML template.

    .DESCRIPTION
        The Engage phase typically reverses Seal actions - re-enabling services,
        restoring settings, etc. For this mock plugin, we process the same
        groups but in Engage context.

        In a real plugin, you might:
        - Have separate groups for Seal vs Engage
        - Filter groups by name or tag
        - Use conditions to skip Seal-only groups during Engage

    .PARAMETER Config
        Plugin configuration from TOML file.

    .PARAMETER Globals
        OS and Platform information for condition evaluation.

    .NOTES
        The Engage phase uses the same template but the action semantics differ:
        - Services might be re-enabled instead of disabled
        - Registry values might be restored instead of set
        - The group processor handles phase-specific behavior
    #>
    param(
        [Parameter()]
        [hashtable]$Config,

        [Parameter()]
        [hashtable]$Globals
    )

    $templatePath = Join-Path $script:PluginScriptRoot 'declarative.toml'

    Write-vSEALLog -Message "Loading declarative template for Engage: $templatePath" -Level VERBOSE

    $template = Import-vSEALTemplate -Path $templatePath

    Write-vSEALLog -Message "Template '$($template.Metadata.Name)' loaded with $($template.Groups.Count) groups" -Level INFO

    # Process groups for Engage phase
    # Note: The same groups are processed, but conditions may filter differently
    # and action semantics may differ based on phase
    foreach ($group in $template.Groups) {
        $result = Invoke-vSEALActionGroup `
            -Group $group `
            -Phase 'Engage' `
            -PluginId 'example-declarative' `
            -Globals $Globals

        $statusMsg = switch ($result.Status) {
            'Completed'           { "$($result.Succeeded)/$($result.Total) succeeded" }
            'CompletedWithErrors' { "$($result.Succeeded)/$($result.Total) succeeded, $($result.Failed) failed" }
            'Skipped'             { "skipped (conditions not met)" }
            'Stopped'             { "stopped at '$($result.StoppedBy)'" }
            'RolledBack'          { "rolled back ($($result.Failed) failures)" }
            default               { $result.Status }
        }

        Write-vSEALLog -Message "Group '$($result.Group)': $statusMsg" -Level INFO
    }

    Write-vSEALLog -Message "Declarative template Engage execution complete" -Level VERBOSE
}

#endregion

# =============================================================================
# END OF DECLARATIVE PLUGIN STUB
# =============================================================================
# The actual actions, conditions, and groups are defined in:
#   declarative.toml
#
# To modify plugin behavior, edit the TOML file - no PowerShell changes needed.
# =============================================================================
