Stepper.psm1

function Clear-StepperState {
    <#
    .SYNOPSIS
        Removes the saved state file.
     
    .DESCRIPTION
        Deletes the stepper state file from disk, effectively resetting
        all progress. Supports -WhatIf and -Confirm for safety.
     
    .PARAMETER Path
        The path to the state file to remove. If not specified, uses the
        default path from Get-StateFilePath.
     
    .EXAMPLE
        Clear-StepperState
         
        Removes the default state file.
     
    .EXAMPLE
        Clear-StepperState -WhatIf
         
        Shows what would happen without actually removing the file.
     
    .EXAMPLE
        Clear-StepperState -Path 'C:\Temp\my-state.json'
         
        Removes a custom state file.
     
    .NOTES
        If the file doesn't exist, a warning is displayed.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Path = (Get-StateFilePath)
    )
    
    if (Test-Path $Path) {
        if ($PSCmdlet.ShouldProcess($Path, "Remove stepper state file")) {
            try {
                Remove-Item -Path $Path -Force -ErrorAction Stop
                Write-Host "State file removed: $Path" -ForegroundColor Green
                Write-Verbose "State successfully cleared"
            }
            catch {
                Write-Error "Failed to remove state file '$Path': $_"
            }
        }
    }
    else {
        Write-Warning "No state file found at: $Path"
    }
}

function Get-StateFilePath {
    <#
    .SYNOPSIS
        Returns the path to the state file.
     
    .DESCRIPTION
        Returns the full path to the stepper state file, creating the
        directory if it doesn't exist.
     
    .PARAMETER FileName
        The name of the state file. Default is 'stepper-state.json'.
     
    .OUTPUTS
        System.String - The full path to the state file.
     
    .EXAMPLE
        $statePath = Get-StateFilePath
         
        Gets the default state file path.
     
    .EXAMPLE
        $statePath = Get-StateFilePath -FileName 'custom-state.json'
         
        Gets a custom state file path.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param(
        [Parameter(Mandatory = $false)]
        [string]$FileName = 'stepper-state.json'
    )
    
    # Store in user profile for persistence across sessions
    # Alternative: Use temp folder for session-only persistence
    $stateDir = Join-Path -Path $env:USERPROFILE -ChildPath '.stepper'
    
    if (-not (Test-Path $stateDir)) {
        New-Item -Path $stateDir -ItemType Directory -Force | Out-Null
        Write-Verbose "Created state directory: $stateDir"
    }
    
    $statePath = Join-Path -Path $stateDir -ChildPath $FileName
    Write-Verbose "State file path: $statePath"
    
    return $statePath
}

function Get-StepperState {
    <#
    .SYNOPSIS
        Loads the stepper state from file, or creates a new one.
     
    .DESCRIPTION
        Attempts to load a saved stepper state from disk. If the file
        doesn't exist or can't be loaded, returns a new empty state.
         
        Converts the JSON PSCustomObject back to a hashtable for easier
        manipulation in PowerShell.
     
    .PARAMETER Path
        The path to the state file. If not specified, uses the default
        path from Get-StateFilePath.
     
    .OUTPUTS
        System.Collections.Hashtable - The loaded or new stepper state.
     
    .EXAMPLE
        $state = Get-StepperState
         
        Loads the state from the default location or creates new.
     
    .EXAMPLE
        $state = Get-StepperState -Path 'C:\Temp\my-state.json'
         
        Loads the state from a custom location.
     
    .NOTES
        If loading fails, warnings are displayed and a new state is returned.
        This ensures the stepper can always proceed.
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Path = (Get-StateFilePath)
    )
    
    if (Test-Path $Path) {
        try {
            Write-Verbose "Loading state from: $Path"
            
            $json = Get-Content -Path $Path -Raw -Encoding UTF8
            $stateObject = $json | ConvertFrom-Json
            
            # Convert PSCustomObject back to hashtable for easier manipulation
            $state = @{
                Version          = $stateObject.Version
                StepperId        = $stateObject.StepperId
                StartedAt        = $stateObject.StartedAt
                LastUpdated      = $stateObject.LastUpdated
                CompletedSteps   = @($stateObject.CompletedSteps)
                CurrentStepIndex = $stateObject.CurrentStepIndex
                Status           = $stateObject.Status
                StepResults      = @{}
                Metadata         = @{}
            }
            
            # Convert nested objects
            if ($stateObject.StepResults) {
                $stateObject.StepResults.PSObject.Properties | ForEach-Object {
                    $state.StepResults[$_.Name] = $_.Value
                }
            }
            
            if ($stateObject.Metadata) {
                $stateObject.Metadata.PSObject.Properties | ForEach-Object {
                    $state.Metadata[$_.Name] = $_.Value
                }
            }
            
            Write-Verbose "State loaded successfully (ID: $($state.StepperId))"
            return $state
        }
        catch {
            Write-Warning "Failed to load state file: $_"
            Write-Warning "Starting with fresh state..."
            return New-StepperState
        }
    }
    else {
        Write-Verbose "No existing state file found, creating new state"
        return New-StepperState
    }
}

function Invoke-StepperStep {
    <#
    .SYNOPSIS
        Executes a single stepper step and tracks the result.
     
    .DESCRIPTION
        Runs the script block for a given stepper step, tracks timing,
        handles errors, and records results in the state object.
     
    .PARAMETER Step
        A hashtable containing the step definition with Name, Description,
        and ScriptBlock properties.
     
    .PARAMETER State
        The stepper state hashtable to update with results.
     
    .PARAMETER AllResults
        Optional hashtable containing results from all previously completed
        steps. Passed to steps that need access to prior results.
     
    .OUTPUTS
        System.Boolean - $true if step succeeded, $false if it failed.
     
    .EXAMPLE
        $success = Invoke-StepperStep -Step $stepDef -State $state
         
        Executes a step and updates the state.
     
    .EXAMPLE
        $success = Invoke-StepperStep -Step $stepDef -State $state -AllResults $allResults
         
        Executes a step that needs access to previous results.
     
    .NOTES
        Results are automatically added to the state object.
        Duration is tracked automatically.
        Errors are caught and logged in the state.
    #>

    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]$Step,
        
        [Parameter(Mandatory = $true)]
        [hashtable]$State,
        
        [Parameter(Mandatory = $false)]
        [hashtable]$AllResults = @{}
    )
    
    $stepName = $Step.Name
    $startTime = Get-Date
    
    Write-Verbose "Executing step: $stepName"
    
    try {
        # Execute the step's script block
        # Check if step needs access to all results (using AcceptsAllResults property from config)
        $result = if ($Step.AcceptsAllResults -eq $true) {
            Write-Verbose "Step accepts AllResults parameter, passing previous results"
            & $Step.ScriptBlock -AllResults $AllResults
        }
        else {
            Write-Verbose "Step does not accept AllResults, executing directly"
            & $Step.ScriptBlock
        }
        
        $duration = (Get-Date) - $startTime
        
        # Record the result
        $State.StepResults[$stepName] = @{
            Status      = 'Completed'
            CompletedAt = Get-Date -Format 'o'
            Duration    = "$([math]::Round($duration.TotalSeconds, 2))s"
            Result      = $result
        }
        
        # Mark as completed
        if ($State.CompletedSteps -notcontains $stepName) {
            $State.CompletedSteps += $stepName
        }
        
        Write-Host "`n ✓ Step completed successfully in $([math]::Round($duration.TotalSeconds, 2))s" -ForegroundColor Green
        Write-Verbose "Step '$stepName' completed successfully"
        
        return $true
    }
    catch {
        $duration = (Get-Date) - $startTime
        
        # Record the failure
        $State.StepResults[$stepName] = @{
            Status       = 'Failed'
            FailedAt     = Get-Date -Format 'o'
            Duration     = "$([math]::Round($duration.TotalSeconds, 2))s"
            Error        = $_.Exception.Message
            ErrorDetails = $_.ScriptStackTrace
        }
        
        Write-Host "`n ✗ Step failed: $($_.Exception.Message)" -ForegroundColor Red
        Write-Host " $($_.ScriptStackTrace)" -ForegroundColor DarkRed
        Write-Verbose "Step '$stepName' failed: $($_.Exception.Message)"
        
        return $false
    }
}

function New-StepperState {
    <#
    .SYNOPSIS
        Creates a new empty stepper state object.
     
    .DESCRIPTION
        Initializes a new hashtable containing the default structure for
        tracking stepper progress, including metadata about the environment.
     
    .OUTPUTS
        System.Collections.Hashtable - A new stepper state object.
     
    .EXAMPLE
        $state = New-StepperState
         
        Creates a new stepper state with default values.
     
    .NOTES
        The state object includes:
        - Version: State file format version
        - StepperId: Unique identifier for this stepper run
        - StartedAt: Timestamp when stepper started
        - LastUpdated: Timestamp of last state update
        - CompletedSteps: Array of completed step names
        - CurrentStepIndex: Index of current/next step
        - Status: Current status (InProgress, Completed, Failed)
        - StepResults: Hashtable of results per step
        - Metadata: Environment information
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param()
    
    Write-Verbose "Creating new stepper state"
    
    return @{
        Version          = '1.0.0'
        StepperId        = [guid]::NewGuid().ToString()
        StartedAt        = Get-Date -Format 'o'
        LastUpdated      = Get-Date -Format 'o'
        CompletedSteps   = @()
        CurrentStepIndex = 0
        Status           = 'InProgress'
        StepResults      = @{}
        Metadata         = @{
            ComputerName = $env:COMPUTERNAME
            UserName     = $env:USERNAME
            PSVersion    = $PSVersionTable.PSVersion.ToString()
            Domain       = $env:USERDNSDOMAIN
        }
    }
}

function Save-StepperState {
    <#
    .SYNOPSIS
        Saves the stepper state to a JSON file.
     
    .DESCRIPTION
        Serializes the stepper state hashtable to JSON format and saves
        it to disk. Updates the LastUpdated timestamp automatically.
     
    .PARAMETER State
        The stepper state hashtable to save.
     
    .PARAMETER Path
        The path where the state file should be saved. If not specified,
        uses the default path from Get-StateFilePath.
     
    .EXAMPLE
        Save-StepperState -State $state
         
        Saves the state to the default location.
     
    .EXAMPLE
        Save-StepperState -State $state -Path 'C:\Temp\my-state.json'
         
        Saves the state to a custom location.
     
    .NOTES
        The state is saved with indentation for readability.
        Throws an error if save fails.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]$State,
        
        [Parameter(Mandatory = $false)]
        [string]$Path = (Get-StateFilePath)
    )
    
    try {
        # Update timestamp
        $State.LastUpdated = Get-Date -Format 'o'
        
        Write-Verbose "Saving state to: $Path"
        
        # Convert to JSON with good depth for nested objects
        $json = $State | ConvertTo-Json -Depth 10 -Compress:$false
        
        # Save to file
        $json | Set-Content -Path $Path -Force -Encoding UTF8
        
        Write-Verbose "State saved successfully"
        Write-Debug "State content: $json"
    }
    catch {
        Write-Error "Failed to save state to '$Path': $_"
        throw
    }
}

function Show-StepperHeader {
    <#
    .SYNOPSIS
        Displays a formatted header for the stepper.
     
    .DESCRIPTION
        Shows a visually formatted header with the stepper tool name
        and version at the start of the stepper.
     
    .PARAMETER Title
        The title to display in the header. Default is "Multi-Step stepper Tool".
     
    .PARAMETER Version
        The version string to display. Default is "1.0.0".
     
    .EXAMPLE
        Show-StepperHeader
         
        Displays the default header.
     
    .EXAMPLE
        Show-StepperHeader -Title "Security stepper" -Version "2.0.0"
         
        Displays a custom header.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Title = "Multi-Step stepper Tool",
        
        [Parameter(Mandatory = $false)]
        [string]$Version = "1.0.0"
    )
    
    $border = "=" * 70
    Write-Host $border -ForegroundColor Cyan
    Write-Host " $Title" -ForegroundColor Cyan
    Write-Host " Version $Version" -ForegroundColor Cyan
    Write-Host $border -ForegroundColor Cyan
    Write-Host ""
}

function Show-StepperProgress {
    <#
    .SYNOPSIS
        Displays current progress summary.
     
    .DESCRIPTION
        Shows a formatted summary of the stepper progress including:
        - stepper ID
        - Start and update timestamps
        - Current status
        - Completed steps with durations
        - Overall percentage complete
     
    .PARAMETER State
        The stepper state hashtable containing progress information.
     
    .PARAMETER TotalSteps
        The total number of steps in the stepper.
     
    .EXAMPLE
        Show-StepperProgress -State $state -TotalSteps 5
         
        Displays progress for a 5-step stepper.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]$State,
        
        [Parameter(Mandatory = $true)]
        [int]$TotalSteps
    )
    
    $completed = $State.CompletedSteps.Count
    $percentComplete = if ($TotalSteps -gt 0) { 
        [math]::Round(($completed / $TotalSteps) * 100, 1) 
    }
    else { 
        0 
    }
    
    Write-Host "`nProgress Summary:" -ForegroundColor Cyan
    Write-Host (" " + ("-" * 50)) -ForegroundColor Gray
    Write-Host " stepper ID : $($State.StepperId)" -ForegroundColor Gray
    Write-Host " Started At : $($State.StartedAt)" -ForegroundColor Gray
    Write-Host " Last Updated : $($State.LastUpdated)" -ForegroundColor Gray
    Write-Host " Status : $($State.Status)" -ForegroundColor $(
        if ($State.Status -eq 'Completed') {
            'Green' 
        } 
        elseif ($State.Status -eq 'Failed') {
            'Red' 
        } 
        else {
            'Yellow' 
        }
    )
    Write-Host " Completed Steps : $completed / $TotalSteps ($percentComplete%)" -ForegroundColor Gray
    Write-Host (" " + ("-" * 50)) -ForegroundColor Gray
    
    if ($State.CompletedSteps.Count -gt 0) {
        Write-Host "`nCompleted Steps:" -ForegroundColor Green
        $State.CompletedSteps | ForEach-Object {
            $stepResult = $State.StepResults[$_]
            $duration = if ($stepResult.Duration) {
                " ($($stepResult.Duration))" 
            }
            else {
                "" 
            }
            Write-Host " ✓ $_$duration" -ForegroundColor Green
        }
    }
    
    Write-Host ""
}

function Show-StepperStepHeader {
    <#
    .SYNOPSIS
        Displays a header for the current stepper step.
     
    .DESCRIPTION
        Shows a formatted header indicating the current step number,
        total steps, and step name.
     
    .PARAMETER StepName
        The name of the current step.
     
    .PARAMETER StepNumber
        The current step number (1-based).
     
    .PARAMETER TotalSteps
        The total number of steps in the stepper.
     
    .EXAMPLE
        Show-StepperStepHeader -StepName "Environment Check" -StepNumber 1 -TotalSteps 5
         
        Displays header for step 1 of 5.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$StepName,
        
        [Parameter(Mandatory = $true)]
        [int]$StepNumber,
        
        [Parameter(Mandatory = $true)]
        [int]$TotalSteps
    )
    
    $border = "-" * 70
    Write-Host "`n$border" -ForegroundColor Cyan
    Write-Host "Step $StepNumber of ${TotalSteps}: $StepName" -ForegroundColor Cyan
    Write-Host "$border" -ForegroundColor Cyan
}

function Test-StepperStateValidity {
    <#
    .SYNOPSIS
        Validates if the saved state is still relevant.
     
    .DESCRIPTION
        Checks the stepper state for validity by verifying:
        - Version compatibility
        - Age of the state (default max 7 days)
        - Valid timestamp format
     
    .PARAMETER State
        The stepper state hashtable to validate.
     
    .PARAMETER MaxAgeDays
        Maximum age in days before state is considered stale.
        Default is 7 days.
     
    .OUTPUTS
        System.Boolean - $true if state is valid, $false otherwise.
     
    .EXAMPLE
        if (Test-StepperStateValidity -State $state) {
            # State is valid, proceed
        }
         
        Validates state with default 7-day age limit.
     
    .EXAMPLE
        if (Test-StepperStateValidity -State $state -MaxAgeDays 30) {
            # State is valid, proceed
        }
         
        Validates state with custom 30-day age limit.
     
    .NOTES
        Displays warnings if state is invalid.
    #>

    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]$State,
        
        [Parameter(Mandatory = $false)]
        [int]$MaxAgeDays = 7
    )
    
    # Check version compatibility
    if ($State.Version -ne '1.0.0') {
        Write-Warning "State file version mismatch. Expected 1.0.0, found $($State.Version)"
        return $false
    }
    
    # Check age
    if ($State.LastUpdated) {
        try {
            $lastUpdate = [DateTime]::Parse($State.LastUpdated)
            $age = (Get-Date) - $lastUpdate
            
            if ($age.TotalDays -gt $MaxAgeDays) {
                Write-Warning "State is $([math]::Round($age.TotalDays, 1)) days old (max: $MaxAgeDays days)"
                return $false
            }
            
            Write-Verbose "State age: $([math]::Round($age.TotalDays, 1)) days (valid)"
        }
        catch {
            Write-Warning "Invalid LastUpdated timestamp in state: $($State.LastUpdated)"
            return $false
        }
    }
    else {
        Write-Warning "State missing LastUpdated timestamp"
        return $false
    }
    
    Write-Verbose "State validation passed"
    return $true
}

function Get-StepperSteps {
    <#
    .SYNOPSIS
        Loads stepper steps from JSON configuration.
     
    .DESCRIPTION
        Reads the stepper-config.json file and dynamically loads
        step scripts from the configured paths. Returns an array of
        hashtables with Name, Description, and ScriptBlock properties.
         
        Steps are loaded from individual .ps1 files in the Steps directory.
        Only enabled steps are included in the returned array.
     
    .PARAMETER ConfigPath
        Path to the configuration JSON file. Defaults to stepper-config.json
        in the module root directory.
     
    .OUTPUTS
        System.Array - Array of step definition hashtables.
     
    .EXAMPLE
        $steps = Get-StepperSteps
        foreach ($step in $steps) {
            # Process each step
        }
         
        Gets all enabled stepper steps from the configuration.
     
    .NOTES
        Configuration file structure:
        {
          "stepperSteps": [
            {
              "name": "StepName",
              "description": "Step description",
              "scriptPath": "Steps/Step-ScriptName.ps1",
              "enabled": true,
              "order": 1,
              "acceptsAllResults": false
            }
          ]
        }
         
        To add new steps:
        1. Create a new .ps1 file in the Steps directory
        2. Add an entry to stepper-config.json
        3. Set "enabled": true and assign an order number
         
        To disable a step without deleting it:
        - Set "enabled": false in the JSON configuration
    #>

    [CmdletBinding()]
    [OutputType([array])]
    param(
        [Parameter(Mandatory = $false)]
        [string]$ConfigPath
    )
    
    Write-Verbose "Loading stepper step configuration"
    
    # Determine module root directory
    $moduleRoot = Split-Path -Parent $PSScriptRoot
    
    # Default config path
    if (-not $ConfigPath) {
        $ConfigPath = Join-Path -Path $moduleRoot -ChildPath 'stepper-config.json'
    }
    
    # Validate config file exists
    if (-not (Test-Path -Path $ConfigPath)) {
        throw "Configuration file not found: $ConfigPath"
    }
    
    Write-Verbose "Reading configuration from: $ConfigPath"
    
    # Load and parse JSON configuration
    try {
        $configContent = Get-Content -Path $ConfigPath -Raw -ErrorAction Stop
        $config = $configContent | ConvertFrom-Json -ErrorAction Stop
    }
    catch {
        throw "Failed to parse configuration file: $_"
    }
    
    # Validate configuration structure
    if (-not $config.stepperSteps) {
        throw "Invalid configuration: 'stepperSteps' property not found"
    }
    
    Write-Verbose "Found $($config.stepperSteps.Count) step(s) in configuration"
    
    # Build step definitions
    $steps = @()
    
    # Sort by order and filter to enabled only
    $enabledSteps = $config.stepperSteps | Where-Object { $_.enabled -eq $true } | Sort-Object -Property order
    
    Write-Verbose "Processing $($enabledSteps.Count) enabled step(s)"
    
    foreach ($stepConfig in $enabledSteps) {
        Write-Verbose "Loading step: $($stepConfig.name)"
        
        # Resolve script path (relative to module root)
        $scriptPath = Join-Path -Path $moduleRoot -ChildPath $stepConfig.scriptPath
        
        # Validate script file exists
        if (-not (Test-Path -Path $scriptPath)) {
            Write-Warning "Step script not found: $scriptPath (skipping step '$($stepConfig.name)')"
            continue
        }
        
        Write-Verbose " Script path: $scriptPath"
        Write-Verbose " Accepts AllResults: $($stepConfig.acceptsAllResults)"
        
        # Load script content
        try {
            $scriptContent = Get-Content -Path $scriptPath -Raw -ErrorAction Stop
            
            # Create scriptblock
            $scriptBlock = [ScriptBlock]::Create($scriptContent)
            
            # Build step definition
            $stepDefinition = @{
                Name              = $stepConfig.name
                Description       = $stepConfig.description
                ScriptBlock       = $scriptBlock
                AcceptsAllResults = $stepConfig.acceptsAllResults
            }
            
            $steps += $stepDefinition
            
            Write-Verbose " ✓ Successfully loaded step: $($stepConfig.name)"
        }
        catch {
            Write-Warning "Failed to load step '$($stepConfig.name)': $_"
            continue
        }
    }
    
    Write-Verbose "Successfully loaded $($steps.Count) step(s)"
    
    if ($steps.Count -eq 0) {
        Write-Warning "No enabled steps were loaded from configuration"
    }
    
    return $steps
}

function Reset-StepperState {
    <#
    .SYNOPSIS
        Clears all saved stepper state.
     
    .DESCRIPTION
        Removes the saved state file, effectively resetting the stepper
        to allow starting fresh. Prompts for confirmation before removing.
         
        Supports -WhatIf and -Confirm parameters.
     
    .EXAMPLE
        Reset-StepperState
         
        Prompts for confirmation then clears the state.
     
    .EXAMPLE
        Reset-StepperState -Confirm:$false
         
        Clears the state without prompting.
     
    .EXAMPLE
        Reset-StepperState -WhatIf
         
        Shows what would happen without actually clearing state.
     
    .NOTES
        This action cannot be undone. All stepper progress will be lost.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param()
    
    Show-StepperHeader
    
    $statePath = Get-StateFilePath
    
    if (Test-Path $statePath) {
        if ($PSCmdlet.ShouldProcess($statePath, "Remove stepper state file and reset all progress")) {
            Clear-StepperState -Confirm:$false
            Write-Host "`nstepper state has been reset." -ForegroundColor Green
            Write-Host "Run 'Start-Stepper' to begin a new stepper." -ForegroundColor Cyan
        }
    }
    else {
        Write-Host "No saved stepper state found." -ForegroundColor Yellow
        Write-Host "Nothing to reset." -ForegroundColor Gray
    }
}

function Show-StepperStatus {
    <#
    .SYNOPSIS
        Displays the current stepper progress without running any steps.
     
    .DESCRIPTION
        Shows the progress summary of the current or last stepper including
        completed steps, current status, and overall progress percentage.
         
        Useful for checking on stepper status without starting or resuming.
     
    .EXAMPLE
        Show-StepperStatus
         
        Displays current stepper progress.
     
    .NOTES
        If no stepper state exists, indicates that no stepper has been started.
    #>

    [CmdletBinding()]
    param()
    
    Show-StepperHeader
    
    $state = Get-StepperState
    $steps = Get-StepperSteps
    
    if ($state.CompletedSteps.Count -eq 0 -and $state.Status -eq 'InProgress' -and 
        [DateTime]::Parse($state.StartedAt) -gt (Get-Date).AddMinutes(-1)) {
        # This is a brand new state that was just created
        Write-Host "No stepper progress found." -ForegroundColor Yellow
        Write-Host "Run 'Start-Stepper' to begin a new stepper." -ForegroundColor Gray
    }
    else {
        Show-StepperProgress -State $state -TotalSteps $steps.Count
        
        if ($state.Status -eq 'InProgress') {
            Write-Host "Run 'Start-Stepper -Resume' to continue the stepper." -ForegroundColor Cyan
        }
        elseif ($state.Status -eq 'Failed') {
            Write-Host "Run 'Start-Stepper -Resume' to retry from the failed step." -ForegroundColor Yellow
        }
        else {
            Write-Host "stepper is complete. Run 'Reset-StepperState' to start fresh." -ForegroundColor Green
        }
    }
}

function Start-Stepper {
    <#
    .SYNOPSIS
        Main function to run the multi-step stepper.
     
    .DESCRIPTION
        Orchestrates the execution of all stepper steps, manages state
        persistence, handles errors, and provides progress feedback.
         
        By default, resumes from the last saved state. Use -Fresh to start over.
     
    .PARAMETER Fresh
        Start a completely new stepper, ignoring any saved state.
     
    .EXAMPLE
        Start-Stepper
         
        Resumes from the last checkpoint (default behavior).
     
    .EXAMPLE
        Start-Stepper -Fresh
         
        Starts a completely new stepper from the beginning.
     
    .NOTES
        State is automatically saved after each step.
        The stepper can be safely interrupted and resumed later.
        Completed steps can be skipped or re-run interactively.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [switch]$Fresh
    )
    
    Show-StepperHeader
    
    # Get all stepper steps
    $steps = Get-StepperSteps
    $totalSteps = $steps.Count
    
    Write-Verbose "Total steps defined: $totalSteps"
    
    # Load or create state (default is to resume)
    $state = if ($Fresh) {
        # User explicitly wants to start fresh
        Write-Host "Starting fresh stepper (ignoring saved state)..." -ForegroundColor Cyan
        New-StepperState
    }
    else {
        # Default behavior: try to resume
        $existingState = Get-StepperState
        
        # Default behavior: try to resume
        $existingState = Get-StepperState
        
        if ($existingState.Status -eq 'Completed') {
            Write-Host "Previous stepper was completed." -ForegroundColor Yellow
            Write-Host "Do you want to start a new stepper? (Y/N): " -NoNewline -ForegroundColor Yellow
            $response = Read-Host
            
            if ($response -eq 'Y') {
                New-StepperState
            }
            else {
                Write-Host "Exiting..." -ForegroundColor Gray
                return
            }
        }
        elseif (-not (Test-StepperStateValidity -State $existingState)) {
            Write-Host "Saved state is invalid or too old." -ForegroundColor Yellow
            Write-Host "Do you want to start fresh? (Y/N): " -NoNewline -ForegroundColor Yellow
            $response = Read-Host
            
            if ($response -eq 'Y') {
                Clear-StepperState -Confirm:$false
                New-StepperState
            }
            else {
                Write-Host "Using existing state anyway..." -ForegroundColor Yellow
                $existingState
            }
        }
        else {
            Write-Host "Resuming from saved state..." -ForegroundColor Cyan
            $existingState
        }
    }
    
    # Show current progress
    Show-StepperProgress -State $state -TotalSteps $totalSteps
    
    # Determine starting point
    $startIndex = $state.CurrentStepIndex
    
    if ($startIndex -ge $totalSteps) {
        $startIndex = 0
    }
    
    Write-Verbose "Starting from step index: $startIndex"
    
    # Execute steps
    for ($i = $startIndex; $i -lt $totalSteps; $i++) {
        $step = $steps[$i]
        
        Show-StepperStepHeader -StepName $step.Name -StepNumber ($i + 1) -TotalSteps $totalSteps
        Write-Host " $($step.Description)" -ForegroundColor Gray
        Write-Host ""
        
        # Check if already completed
        if ($state.CompletedSteps -contains $step.Name) {
            Write-Host " This step was already completed." -ForegroundColor Yellow
            Write-Host " Do you want to skip it? (Y/N): " -NoNewline -ForegroundColor Yellow
            $skip = Read-Host
            
            if ($skip -eq 'Y') {
                Write-Host " Skipping..." -ForegroundColor Gray
                continue
            }
            else {
                Write-Host " Re-running..." -ForegroundColor Gray
            }
        }
        
        # Prepare all results for steps that need them
        $allResults = @{}
        foreach ($completedStep in $state.CompletedSteps) {
            if ($state.StepResults.ContainsKey($completedStep)) {
                $allResults[$completedStep] = $state.StepResults[$completedStep].Result
            }
        }
        
        # Execute the step
        $success = Invoke-StepperStep -Step $step -State $state -AllResults $allResults
        
        # Update current step index
        $state.CurrentStepIndex = $i + 1
        
        # Save state after each step
        Save-StepperState -State $state
        
        if (-not $success) {
            $state.Status = 'Failed'
            Save-StepperState -State $state
            
            Write-Host "`nstepper stopped due to error." -ForegroundColor Red
            Write-Host "State saved. You can resume later with the -Resume switch." -ForegroundColor Yellow
            Write-Host "State file location: $(Get-StateFilePath)" -ForegroundColor Gray
            return
        }
        
        # Prompt to continue after each step (except last)
        if ($i -lt ($totalSteps - 1)) {
            Write-Host "`n Press Enter to continue to the next step, or Ctrl+C to stop..." -ForegroundColor Cyan
            Read-Host | Out-Null
        }
    }
    
    # Mark as completed
    $state.Status = 'Completed'
    $state.CompletedAt = Get-Date -Format 'o'
    Save-StepperState -State $state
    
    # Show final summary
    Write-Host "`n" + ("=" * 70) -ForegroundColor Green
    Write-Host " stepper Complete!" -ForegroundColor Green
    Write-Host ("=" * 70) -ForegroundColor Green
    
    Show-StepperProgress -State $state -TotalSteps $totalSteps
    
    $totalDuration = ([DateTime]::Parse($state.CompletedAt)) - ([DateTime]::Parse($state.StartedAt))
    Write-Host "Total Duration: $([math]::Round($totalDuration.TotalMinutes, 2)) minutes`n" -ForegroundColor Gray
}



# Export functions and aliases as required
Export-ModuleMember -Function @('Get-StepperSteps', 'Reset-StepperState', 'Show-StepperStatus', 'Start-Stepper') -Alias @()