# Backup-UDCData.ps1 - Capture UDC's CurrentData.json + ArchivedData/ to the
# SFLD share, keyed by the PC's current machine number. Runs LOCALLY on the
# old PC before retirement; the new PC restores during its first
# placeholder-to-real machine-number assignment via Update-MachineNumber.ps1.
#
# DESIGN: backup lives at <share>\<machine>\ root. Presence of CurrentData.json
# at that root means "available to restore". Restore consumes by moving content
# into <machine>\migrated\<timestamp>\, leaving the root empty so it can't
# be replayed.
#
# USAGE:
#   - Direct:           powershell -NoProfile -ExecutionPolicy Bypass -File Backup-UDCData.ps1
#   - Wrapper:          Backup-UDCData.bat (handles the bypass + elevation prompts)
#   - Remote (WinRM):   ../powershell/remote-execution/Backup-UDCData-Remote.ps1

[CmdletBinding()]
param(
    # Override auto-detection for unusual cases. Defaults to whatever UDC
    # currently has in C:\ProgramData\UDC\udc_settings.json.
    [string]$MachineNumber,

    # Override the share path. Defaults to the canonical SFLD location.
    [string]$BackupShareRoot = '\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\backup\udc',

    # Local UDC data root. Default matches the vendor install path.
    [string]$UdcDataDir = 'C:\ProgramData\UDC',

    # Cred for the SFLD share. If omitted, the current session's identity
    # is used (works for SYSTEM-context runs and for local interactive
    # admin sessions where the user has cached SFLD creds via SFLD-Reg).
    [System.Management.Automation.PSCredential]$Credential,

    # If the destination already has a backup for this machine, append a
    # timestamped suffix instead of overwriting. Default: overwrite (latest
    # backup wins; the prior one only matters if the new PC didn't restore
    # before this re-backup).
    [switch]$KeepPriorBackup
)

$ErrorActionPreference = 'Stop'
$logDir = 'C:\Logs\UDC'
if (-not (Test-Path $logDir)) {
    try { New-Item -Path $logDir -ItemType Directory -Force | Out-Null } catch { $logDir = $env:TEMP }
}
$logFile = Join-Path $logDir ("Backup-UDCData_$(Get-Date -Format 'yyyyMMdd-HHmmss').log")
try { Start-Transcript -Path $logFile -Append -Force | Out-Null } catch {}

function Log {
    param([string]$Msg, [string]$Level = 'INFO')
    $ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    Write-Host "[$ts][$Level] $Msg"
}

Log "==============================================="
Log "Backup-UDCData starting"
Log "Hostname:       $env:COMPUTERNAME"
Log "User:           $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
Log "UDC data dir:   $UdcDataDir"
Log "Backup share:   $BackupShareRoot"
Log "Log file:       $logFile"
Log "==============================================="

# --- Resolve machine number ---
if (-not $MachineNumber) {
    $settings = Join-Path $UdcDataDir 'udc_settings.json'
    if (-not (Test-Path $settings)) {
        Log "udc_settings.json not found at $settings - cannot auto-detect machine number" 'ERROR'
        Log "Re-run with -MachineNumber <num> to override"
        try { Stop-Transcript | Out-Null } catch {}
        exit 2
    }
    try {
        $json = Get-Content $settings -Raw | ConvertFrom-Json
        $MachineNumber = $json.GeneralSettings.MachineNumber
    } catch {
        Log "Failed to parse udc_settings.json: $_" 'ERROR'
        try { Stop-Transcript | Out-Null } catch {}
        exit 3
    }
}
if (-not $MachineNumber -or $MachineNumber -eq '9999' -or $MachineNumber -notmatch '^\d+$') {
    Log "Invalid or placeholder machine number: '$MachineNumber'. Aborting." 'ERROR'
    Log "(Backups for placeholder 9999 would collide across PCs and aren't useful.)"
    try { Stop-Transcript | Out-Null } catch {}
    exit 4
}
Log "Resolved machine number: $MachineNumber"

# --- Verify source files exist ---
$srcCurrent = Join-Path $UdcDataDir 'CurrentData.json'
$srcArchive = Join-Path $UdcDataDir 'ArchivedData'

$haveCurrent = Test-Path -LiteralPath $srcCurrent
$haveArchive = Test-Path -LiteralPath $srcArchive

if (-not $haveCurrent -and -not $haveArchive) {
    Log "Neither CurrentData.json nor ArchivedData/ exists under $UdcDataDir. Nothing to back up." 'WARN'
    try { Stop-Transcript | Out-Null } catch {}
    exit 0
}
Log "CurrentData.json present:  $haveCurrent"
Log "ArchivedData/ present:      $haveArchive"

# --- Mount share if credentials supplied (otherwise rely on ambient auth) ---
$psDrive = $null
$dest = Join-Path $BackupShareRoot $MachineNumber
if ($Credential) {
    try {
        $psDrive = New-PSDrive -Name UDCBKP -PSProvider FileSystem -Root $BackupShareRoot -Credential $Credential -ErrorAction Stop
        Log "Share mounted as UDCBKP: with explicit credentials"
        $dest = "UDCBKP:\$MachineNumber"
    } catch {
        Log "Failed to mount $BackupShareRoot with supplied credentials: $_" 'ERROR'
        try { Stop-Transcript | Out-Null } catch {}
        exit 5
    }
}

# --- Create destination dir ---
try {
    if (-not (Test-Path -LiteralPath $dest)) {
        New-Item -ItemType Directory -Path $dest -Force | Out-Null
        Log "Created destination: $dest"
    }
} catch {
    Log "Failed to create destination $dest : $_" 'ERROR'
    if ($psDrive) { Remove-PSDrive -Name UDCBKP -Force }
    try { Stop-Transcript | Out-Null } catch {}
    exit 6
}

# --- Optional: rotate prior backup at this bay if -KeepPriorBackup ---
if ($KeepPriorBackup) {
    $existingMarker = Join-Path $dest 'CurrentData.json'
    if (Test-Path -LiteralPath $existingMarker) {
        $rotateName = Join-Path $dest ('superseded-' + (Get-Date -Format 'yyyyMMdd-HHmmss'))
        New-Item -ItemType Directory -Path $rotateName -Force | Out-Null
        Get-ChildItem $dest -Force | Where-Object { $_.Name -ne 'migrated' -and $_.Name -ne (Split-Path $rotateName -Leaf) } | ForEach-Object {
            Move-Item -LiteralPath $_.FullName -Destination $rotateName -Force
        }
        Log "Prior backup rotated into $rotateName (KeepPriorBackup=true)"
    }
}

# --- Copy CurrentData.json ---
$copiedCurrent = $false
$currentBytes = 0
if ($haveCurrent) {
    try {
        Copy-Item -LiteralPath $srcCurrent -Destination (Join-Path $dest 'CurrentData.json') -Force -ErrorAction Stop
        $currentBytes = (Get-Item -LiteralPath $srcCurrent).Length
        $copiedCurrent = $true
        Log "Copied CurrentData.json ($currentBytes bytes)"
    } catch {
        Log "Failed to copy CurrentData.json: $_" 'ERROR'
    }
}

# --- Copy ArchivedData/ recursively ---
$copiedArchive = $false
$archiveBytes = 0
$archiveFiles = 0
if ($haveArchive) {
    try {
        $destArchive = Join-Path $dest 'ArchivedData'
        if (Test-Path -LiteralPath $destArchive) {
            Remove-Item -LiteralPath $destArchive -Recurse -Force -ErrorAction Stop
        }
        Copy-Item -LiteralPath $srcArchive -Destination $destArchive -Recurse -Force -ErrorAction Stop
        $copiedArchive = $true
        $archiveItems = Get-ChildItem -LiteralPath $destArchive -Recurse -File -ErrorAction SilentlyContinue
        $archiveBytes = ($archiveItems | Measure-Object Length -Sum).Sum
        $archiveFiles = $archiveItems.Count
        Log "Copied ArchivedData/ ($archiveFiles files, $archiveBytes bytes)"
    } catch {
        Log "Failed to copy ArchivedData/: $_" 'ERROR'
    }
}

# --- Drop a small backup.manifest.json next to the data for forensics ---
try {
    $manifest = [ordered]@{
        BackedUpAt        = (Get-Date -Format 'o')
        SourceHostname    = $env:COMPUTERNAME
        SourceUser        = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
        MachineNumber     = $MachineNumber
        CurrentDataPresent = $copiedCurrent
        CurrentDataBytes  = $currentBytes
        ArchivedDataPresent = $copiedArchive
        ArchivedDataFiles  = $archiveFiles
        ArchivedDataBytes  = $archiveBytes
    }
    $manifest | ConvertTo-Json | Set-Content -Path (Join-Path $dest 'backup.manifest.json') -Encoding UTF8
    Log "Wrote backup.manifest.json"
} catch {
    Log "Manifest write failed (non-fatal): $_" 'WARN'
}

# --- Tear down mount ---
if ($psDrive) {
    try { Remove-PSDrive -Name UDCBKP -Force } catch {}
}

Log "==============================================="
Log "Backup complete:"
Log "  Bay:              $MachineNumber"
Log "  Destination:      $BackupShareRoot\$MachineNumber\"
Log "  CurrentData.json: $(if ($copiedCurrent) {'OK ('+$currentBytes+' bytes)'} else {'MISSING'})"
Log "  ArchivedData/:     $(if ($copiedArchive) {'OK ('+$archiveFiles+' files, '+$archiveBytes+' bytes)'} else {'MISSING'})"
Log "==============================================="
try { Stop-Transcript | Out-Null } catch {}
exit 0
