<#
.SYNOPSIS
    Translates a v1 OtOpcUa.Host appsettings.json into a v2 DriverInstance.DriverConfig JSON
    blob suitable for upserting into the central Configuration DB.

.DESCRIPTION
    Phase 2 Stream D.3 — moves the legacy MxAccess + GalaxyRepository + Historian sections out
    of node-local appsettings.json and into the central DB so each node only needs Cluster.NodeId
    + ClusterId + DB conn (per decision #18). Idempotent + dry-run-able.

    Output shape matches the Galaxy DriverType schema in `docs/v2/plan.md` §"Galaxy DriverConfig":

        {
          "MxAccess":  { "ClientName": "...", "RequestTimeoutSeconds": 30 },
          "Database":  { "ConnectionString": "...", "PollIntervalSeconds": 60 },
          "Historian": { "Enabled": false }
        }

.PARAMETER AppSettingsPath
    Path to the v1 appsettings.json. Defaults to ../../src/ZB.MOM.WW.OtOpcUa.Host/appsettings.json
    relative to the script.

.PARAMETER OutputPath
    Where to write the generated DriverConfig JSON. Defaults to stdout.

.PARAMETER DryRun
    Print what would be written without writing.

.EXAMPLE
    pwsh ./Migrate-AppSettings-To-DriverConfig.ps1 -AppSettingsPath C:\OtOpcUa\appsettings.json -OutputPath C:\tmp\galaxy-driverconfig.json
#>
[CmdletBinding()]
param(
    [string]$AppSettingsPath,
    [string]$OutputPath,
    [switch]$DryRun
)

$ErrorActionPreference = 'Stop'

if (-not $AppSettingsPath) {
    $AppSettingsPath = Join-Path (Split-Path -Parent $PSScriptRoot) '..\src\ZB.MOM.WW.OtOpcUa.Host\appsettings.json'
}

if (-not (Test-Path $AppSettingsPath)) {
    Write-Error "AppSettings file not found: $AppSettingsPath"
    exit 1
}

$src = Get-Content -Raw $AppSettingsPath | ConvertFrom-Json

$mx = $src.MxAccess
$gr = $src.GalaxyRepository
$hi = $src.Historian

$driverConfig = [ordered]@{
    MxAccess = [ordered]@{
        ClientName            = $mx.ClientName
        NodeName              = $mx.NodeName
        GalaxyName            = $mx.GalaxyName
        RequestTimeoutSeconds = $mx.ReadTimeoutSeconds
        WriteTimeoutSeconds   = $mx.WriteTimeoutSeconds
        MaxConcurrentOps      = $mx.MaxConcurrentOperations
        MonitorIntervalSec    = $mx.MonitorIntervalSeconds
        AutoReconnect         = $mx.AutoReconnect
        ProbeTag              = $mx.ProbeTag
    }
    Database = [ordered]@{
        ConnectionString          = $gr.ConnectionString
        ChangeDetectionIntervalSec = $gr.ChangeDetectionIntervalSeconds
        CommandTimeoutSeconds     = $gr.CommandTimeoutSeconds
        ExtendedAttributes        = $gr.ExtendedAttributes
        Scope                     = $gr.Scope
        PlatformName              = $gr.PlatformName
    }
    Historian = [ordered]@{
        Enabled = if ($null -ne $hi -and $null -ne $hi.Enabled) { $hi.Enabled } else { $false }
    }
}

# Strip null-valued leaves so the resulting JSON is compact and round-trippable.
function Remove-Nulls($obj) {
    $keys = @($obj.Keys)
    foreach ($k in $keys) {
        if ($null -eq $obj[$k]) { $obj.Remove($k) | Out-Null }
        elseif ($obj[$k] -is [System.Collections.Specialized.OrderedDictionary]) { Remove-Nulls $obj[$k] }
    }
}
Remove-Nulls $driverConfig

$json = $driverConfig | ConvertTo-Json -Depth 8

if ($DryRun) {
    Write-Host "=== DriverConfig (dry-run, would write to $OutputPath) ==="
    Write-Host $json
    return
}

if ($OutputPath) {
    $dir = Split-Path -Parent $OutputPath
    if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
    Set-Content -Path $OutputPath -Value $json -Encoding UTF8
    Write-Host "Wrote DriverConfig to $OutputPath"
}
else {
    $json
}
