#Requires -Version 7.4

function Save-vSEALBaseline {
    <#
    .SYNOPSIS
        Saves the accumulated baseline entries to persistent storage.

    .DESCRIPTION
        Creates a baseline folder with timestamp ID containing a manifest file
        and per-plugin JSON files. Uses atomic write pattern (temp file + rename + flush)
        to ensure durability against abrupt termination.

        The baseline folder structure:
        - YYYYMMDD_HHMMSS/
          - _manifest.json (metadata and plugin summary)
          - {pluginId}.json (per-plugin entries)

    .PARAMETER Id
        Optional custom baseline ID. If not specified, a timestamp ID in
        YYYYMMDD_HHMMSS format is auto-generated. Used by rollback to create
        named forward baselines (e.g., 'pre-rollback-20260215_143022').

    .PARAMETER ConfigPath
        Path to the configuration file used for Seal phase. Stored in manifest.

    .PARAMETER Config
        Optional hashtable containing vSEAL configuration. If the configuration
        contains a baseline.path setting, that path will be used for storage.

    .PARAMETER Status
        The completion status of the Seal operation: 'complete' or 'incomplete'.
        Defaults to 'complete'.

    .PARAMETER Phase
        Phase to record in manifest. Defaults to 'Seal'. Set to 'rollback'
        for forward baselines created before rollback operations.

    .PARAMETER SourceBaseline
        Optional baseline ID that this forward baseline relates to. Stored
        in manifest for traceability (e.g., links a pre-rollback baseline
        to the baseline being rolled back).

    .PARAMETER PassThru
        If specified, returns the baseline ID after saving.

    .EXAMPLE
        Save-vSEALBaseline -ConfigPath 'C:\vSEAL\config.toml'

        Saves baseline entries to the default location with status 'complete'.

    .EXAMPLE
        $id = Save-vSEALBaseline -ConfigPath 'C:\vSEAL\config.toml' -PassThru

        Saves baseline and returns the timestamp ID for later retrieval.

    .EXAMPLE
        Save-vSEALBaseline -ConfigPath 'C:\vSEAL\config.toml' -Status incomplete

        Saves baseline with incomplete status (e.g., after partial execution).

    .EXAMPLE
        Save-vSEALBaseline -Id 'pre-rollback-20260215_143022' -Phase 'rollback' -SourceBaseline '20260215_143022' -ConfigPath 'C:\vSEAL\config.toml' -PassThru

        Saves a forward baseline with custom ID before rollback operation.

    .OUTPUTS
        [string] The baseline ID if -PassThru is specified; otherwise [void].
    #>
    [CmdletBinding()]
    [OutputType([string])]
    [OutputType([void])]
    param(
        [Parameter()]
        [string]$Id,

        [Parameter()]
        [string]$ConfigPath,

        [Parameter()]
        [hashtable]$Config,

        [Parameter()]
        [ValidateSet('complete', 'incomplete')]
        [string]$Status = 'complete',

        [Parameter()]
        [string]$Phase = 'Seal',

        [Parameter()]
        [string]$SourceBaseline,

        [Parameter()]
        [switch]$PassThru
    )

    # Get accumulated context
    $context = Get-vSEALBaselineContext

    # Check for empty context
    if ($null -eq $context -or $context.Count -eq 0) {
        Write-Warning "No baseline entries to save. Initialize context and add entries before saving."
        return
    }

    # Collect OS and platform information
    $osInfo = Get-vSEALOperatingSystemInfo
    $hypervisorInfo = Get-HypervisorPlatformData
    $azureInfo = Get-vSEALAzurePlatformData

    # Generate or use provided baseline ID
    if ([string]::IsNullOrEmpty($Id)) {
        $id = Get-Date -Format 'yyyyMMdd_HHmmss'
    } else {
        $id = $Id
    }

    # Resolve storage location
    $basePath = Resolve-vSEALBaselinePath -Config $Config

    # Create baseline folder path
    $baselineDir = Join-Path $basePath $id

    # Check for existing baseline with same ID (conflict detection for forward baselines)
    if (Test-Path -Path $baselineDir -PathType Container) {
        throw "Baseline '$id' already exists. Delete it first or use a different ID."
    }

    Write-vSEALLog "Saving baseline to: $baselineDir" -Level VERBOSE

    # Create baseline directory
    $null = New-Item -Path $baselineDir -ItemType Directory -Force
    Write-vSEALLog "Created baseline directory: $baselineDir" -Level VERBOSE

    # Build OS data for manifest (camelCase keys for JSON)
    $osData = @{
        name          = $osInfo.Name
        edition       = $osInfo.Edition
        version       = $osInfo.Version.ToString()
        buildNumber   = $osInfo.BuildNumber
        releaseId     = $osInfo.ReleaseId
        architecture  = $osInfo.Architecture.ToString()
        isWorkstation = $osInfo.IsWorkstation
        isServer      = $osInfo.IsServer
    }

    # Build platform data for manifest
    $platformData = @{
        hypervisor    = $hypervisorInfo.Hypervisor
        isVMware      = $hypervisorInfo.IsVMware
        isHyperV      = $hypervisorInfo.IsHyperV
        isNutanixAHV  = $hypervisorInfo.IsNutanixAHV
        isXenServer   = $hypervisorInfo.IsXenServer
        isAzure       = ($null -ne $azureInfo)
        azureMetadata = $azureInfo
    }

    # Backward compatibility: keep osBuild as standalone field
    $osBuild = $osInfo.BuildNumber

    # Build plugin summary and count stats
    $pluginSummary = @{}
    $totalPlugins = 0

    foreach ($pluginId in $context.Keys) {
        $entries = $context[$pluginId]
        $totalPlugins++

        # Count success/failed (for now all are considered successful since they were recorded)
        $pluginSummary[$pluginId] = @{
            actions = $entries.Count
            success = $entries.Count
            failed  = 0
        }
    }

    # Build manifest
    $manifest = @{
        id          = $id
        created     = (Get-Date).ToUniversalTime().ToString('o')
        status      = $Status
        phase       = $Phase
        configPath  = $ConfigPath
        machineName = $env:COMPUTERNAME
        osBuild     = $osBuild
        os          = $osData
        platform    = $platformData
        plugins     = $pluginSummary
    }
    if (-not [string]::IsNullOrEmpty($SourceBaseline)) {
        $manifest.sourceBaseline = $SourceBaseline
    }

    # Write manifest using atomic pattern
    $manifestPath = Join-Path $baselineDir '_manifest.json'
    $manifestTempPath = "$manifestPath.tmp"

    $manifest | ConvertTo-Json -Depth 10 | Set-Content -Path $manifestTempPath -Encoding utf8
    Move-Item -Path $manifestTempPath -Destination $manifestPath -Force
    [System.IO.File]::OpenWrite($manifestPath).Close()

    Write-vSEALLog "Wrote manifest: _manifest.json" -Level VERBOSE

    # Write per-plugin files
    foreach ($pluginId in $context.Keys) {
        $entries = $context[$pluginId]

        # Build plugin file structure
        $pluginData = @{
            plugin    = $pluginId
            timestamp = (Get-Date).ToUniversalTime().ToString('o')
            entries   = @($entries)
        }

        # Write plugin file using atomic pattern (v2: flat plugin ID as filename)
        $pluginFileName = "$pluginId.json"
        $pluginFilePath = Join-Path $baselineDir $pluginFileName
        $pluginTempPath = "$pluginFilePath.tmp"

        $pluginData | ConvertTo-Json -Depth 10 | Set-Content -Path $pluginTempPath -Encoding utf8
        Move-Item -Path $pluginTempPath -Destination $pluginFilePath -Force
        [System.IO.File]::OpenWrite($pluginFilePath).Close()

        Write-vSEALLog "Wrote plugin file: $pluginFileName" -Level VERBOSE
    }

    # Clear context after successful save
    Clear-vSEALBaselineContext

    # Emit baseline.create event for orchestrator tracking
    Write-vSEALLog "Baseline created: $id" -Level INFO `
        -Type 'baseline.create' `
        -Data @{
            baselineId = $id
            createdAt  = (Get-Date).ToUniversalTime().ToString('o')
        }

    Write-vSEALLog "Baseline saved: $id with $totalPlugins plugins on $($osInfo.Name)" -Level VERBOSE

    if ($PassThru) {
        return $id
    }
}
