# maint_doc_oneoff.ps1
# But : créer/mettre à jour un fichier TXT de gouvernance avec backup obligatoire,
#       aperçu des actions (preview), confirmation, exécution, archivage et log.
# Environnement : Windows PowerShell (sans droits admin), ASCII par défaut.
# Usage : coller tel quel dans la console, ajuster les variables bloc [CONFIG], puis Entrée.

# =========================
# [CONFIG] A ADAPTER
# =========================
$TargetPath        = "\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\latest_cycle.txt"
$ArchiveDir        = "\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\_archives\2025-10-15_SOURCE-OF-TRUTH"
$OldVersionsDir    = "\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\_old_versions"
$RegistryLogPath   = "C:\Logs_Gouvernance\registry_activity.log"  # exigé pour exécution
$FileEncoding      = "ascii"   # "ascii" (préféré) ou "utf8NoBOM"

# Contenu du fichier cible (ASCII recommandé)
$Content = @"
===========================================================
LATEST CYCLE — CHATGPT-GOUVERNANCE-PROJETS
===========================================================

Cycle : SOURCE-OF-TRUTH — 2025-10-15
Commit final : F92B13D7E55C8A79E3F4D3A52BC71F490CA928AB
Snapshot : snapshot_2025-10-15_fusion_history.json
Rapport : RAPPORT_COHERENCE_XREF_2025-10-15.txt

===========================================================
"@

# Déplacement auto d’une éventuelle ancienne version du fichier vers _old_versions (True/False)
$MoveOldToOldVersions = $true

# =========================
# [FONCTIONS]
# =========================

function New-ParentDirectory {
    param([string]$Path)
    $dir = Split-Path -Path $Path -Parent
    if (-not [string]::IsNullOrWhiteSpace($dir) -and -not (Test-Path -LiteralPath $dir)) {
        New-Item -ItemType Directory -LiteralPath $dir | Out-Null
    }
}

function Get-Timestamp {
    (Get-Date).ToString("yyyy-MM-dd_HH-mm-ss")
}

function Get-FileSha1 {
    param([string]$Path)
    if (-not (Test-Path -LiteralPath $Path)) { return $null }
    $sha1 = [System.Security.Cryptography.SHA1]::Create()
    $fs   = [System.IO.File]::OpenRead($Path)
    try {
        $hash = $sha1.ComputeHash($fs)
        ($hash | ForEach-Object { $_.ToString("x2") }) -join ""
    } finally {
        $fs.Dispose()
        $sha1.Dispose()
    }
}

function Write-TextFile {
    param(
        [string]$Path,
        [string]$Text,
        [ValidateSet("ascii","utf8NoBOM")][string]$Encoding = "ascii"
    )
    New-ParentDirectory -Path $Path
    if ($Encoding -eq "ascii") {
        [System.IO.File]::WriteAllText($Path, $Text, [System.Text.Encoding]::ASCII)
    } else {
        $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
        [System.IO.File]::WriteAllText($Path, $Text, $utf8NoBom)
    }
}

function Append-Log {
    param([string]$LogPath, [string]$Line)
    New-ParentDirectory -Path $LogPath
    $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
    $full = "$ts | $Line"
    Add-Content -LiteralPath $LogPath -Value $full -Encoding ASCII
}

# =========================
# [PREVIEW]
# =========================

$ts = Get-Timestamp
$preview = @()

if ([string]::IsNullOrWhiteSpace($RegistryLogPath)) {
    $preview += "[ERROR] RegistryLogPath est vide (obligatoire)."
}

$existing = $null
$existingSha1 = $null
if (Test-Path -LiteralPath $TargetPath) {
    $existing = $TargetPath
    $existingSha1 = Get-FileSha1 -Path $TargetPath
}

$backupPath = $null
if ($existing) {
    $backupPath = "{0}.{1}.bak" -f $TargetPath, $ts
    $preview += "[INFO] Fichier cible existe : $TargetPath"
    $preview += "[INFO] SHA1 existant : $existingSha1"
    $preview += "[PLAN] Création d’un backup : $backupPath"
    if ($MoveOldToOldVersions) {
        $preview += "[PLAN] Après écriture, déplacement de l’ancienne version vers : $OldVersionsDir"
    }
} else {
    $preview += "[INFO] Fichier cible inexistant : $TargetPath (création)"
}

$preview += "[PLAN] Ecriture du fichier (encodage=$FileEncoding)"
$preview += "[PLAN] Journalisation append dans : $RegistryLogPath"

"[PREVIEW] Opérations prévues :"
$preview | ForEach-Object { $_ }

# =========================
# [CONFIRMATION]
# =========================
$confirm = Read-Host "Confirmer l’exécution ? (O/N)"
if ($confirm -notin @('O','o','Y','y')) {
    "[ABORT] Opérations annulées par l’utilisateur."
    return
}

if ([string]::IsNullOrWhiteSpace($RegistryLogPath)) {
    "[ERROR] RegistryLogPath non défini. Abandon."
    return
}

# =========================
# [EXECUTION]
# =========================

try {
    # 1) Backup si le fichier existe
    if ($existing) {
        Copy-Item -LiteralPath $TargetPath -Destination $backupPath -Force
    }

    # 2) Ecriture du nouveau contenu
    Write-TextFile -Path $TargetPath -Text $Content -Encoding $FileEncoding

    # 3) Déplacement de l’ancienne version vers _old_versions si demandé
    if ($existing -and $MoveOldToOldVersions) {
        New-ParentDirectory -Path $OldVersionsDir
        $base = Split-Path -Leaf $TargetPath
        $oldName = Join-Path $OldVersionsDir ("{0}.old.{1}.txt" -f $base, $ts)
        Move-Item -LiteralPath $backupPath -Destination $oldName -Force
        $backupPath = $oldName
    }

    # 4) SHA1 final
    $newSha1 = Get-FileSha1 -Path $TargetPath

    # 5) Log append
    $line = "UPDATE | target=$TargetPath | sha1=$newSha1 | backup=$backupPath | enc=$FileEncoding"
    Append-Log -LogPath $RegistryLogPath -Line $line

    "[OK] Mise à jour effectuée."
    "[OK] Fichier : $TargetPath"
    if ($backupPath) { "[OK] Ancienne version : $backupPath" }
    "[OK] SHA1 nouveau : $newSha1"
    "[OK] Log : $RegistryLogPath"
}
catch {
    "[ERROR] " + $_.Exception.Message
    exit 1
}
