[CmdletBinding()]
param([switch]$SkipProductionDeploy)

Set-StrictMode -Version 2.0
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Xaml

$PackageRoot = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..\..') -ErrorAction Stop).ProviderPath.TrimEnd([System.IO.Path]::DirectorySeparatorChar,[System.IO.Path]::AltDirectorySeparatorChar)
$TargetVersion = '1.43.0'
$UpdaterVersion = '3.4.0'
$WorkerScript = Join-Path $PSScriptRoot 'Vendoo.Updater.Worker34.ps1'
$WorkerHostScript = Join-Path $PSScriptRoot 'Vendoo.Updater.Host.ps1'
$LocalRoot = Join-Path $env:LOCALAPPDATA 'Vendoo\Updater'
$RuntimeRoot = Join-Path $LocalRoot 'runtime'
$SessionRoot = Join-Path $LocalRoot 'sessions'
New-Item -ItemType Directory -Path $RuntimeRoot,$SessionRoot -Force | Out-Null

$createdNew = $false
$mutex = [System.Threading.Mutex]::new($true, 'Local\VendooProductionUpdater', [ref]$createdNew)
if (-not $createdNew) {
  [System.Windows.MessageBox]::Show('Der Vendoo-Updater läuft bereits. Bitte das vorhandene Fenster verwenden.','Vendoo Updater',[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Information) | Out-Null
  return
}

$xaml = @'
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Vendoo Production Updater" Width="1080" Height="720" MinWidth="960" MinHeight="650"
        WindowStartupLocation="CenterScreen" Background="#0F1115" Foreground="#EEF1F5"
        FontFamily="Segoe UI" ResizeMode="CanResize">
  <Window.Resources>
    <SolidColorBrush x:Key="Panel" Color="#171A20"/>
    <SolidColorBrush x:Key="Panel2" Color="#1D2129"/>
    <SolidColorBrush x:Key="Border" Color="#2B313C"/>
    <SolidColorBrush x:Key="Muted" Color="#9AA4B2"/>
    <SolidColorBrush x:Key="Accent" Color="#4F8CFF"/>
    <Style TargetType="Button">
      <Setter Property="Foreground" Value="#EEF1F5"/><Setter Property="Background" Value="#252B35"/>
      <Setter Property="BorderBrush" Value="#343C49"/><Setter Property="Padding" Value="16,9"/>
      <Setter Property="FontWeight" Value="SemiBold"/><Setter Property="Cursor" Value="Hand"/>
      <Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button">
        <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="7" Padding="{TemplateBinding Padding}">
          <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Border><ControlTemplate.Triggers>
          <Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="#303744"/></Trigger>
          <Trigger Property="IsEnabled" Value="False"><Setter Property="Opacity" Value="0.42"/></Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate></Setter.Value></Setter>
    </Style>
    <Style x:Key="PrimaryButton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
      <Setter Property="Background" Value="#2E6FE8"/><Setter Property="BorderBrush" Value="#4F8CFF"/>
    </Style>
  </Window.Resources>
  <Grid>
    <Grid.RowDefinitions><RowDefinition Height="76"/><RowDefinition Height="*"/><RowDefinition Height="68"/></Grid.RowDefinitions>
    <Border Grid.Row="0" Background="#14171C" BorderBrush="#252B35" BorderThickness="0,0,0,1">
      <Grid Margin="28,0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
        <StackPanel VerticalAlignment="Center">
          <TextBlock FontSize="23" FontWeight="SemiBold" Text="Vendoo Production Updater"/>
          <TextBlock Foreground="{StaticResource Muted}" FontSize="12" Margin="0,4,0,0" Text="Sicherer Release-, GitHub- und Coolify-Ablauf"/>
        </StackPanel>
        <Border Grid.Column="1" Background="#202631" BorderBrush="#343C49" BorderThickness="1" CornerRadius="8" Padding="14,8" VerticalAlignment="Center">
          <StackPanel Orientation="Horizontal"><TextBlock Text="ZIEL  "/><TextBlock FontWeight="Bold" Text="1.43.0"/></StackPanel>
        </Border>
      </Grid>
    </Border>

    <Grid Grid.Row="1" Margin="24,22,24,16">
      <Grid.ColumnDefinitions><ColumnDefinition Width="300"/><ColumnDefinition Width="18"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions>
      <Border Grid.Column="0" Background="{StaticResource Panel}" BorderBrush="{StaticResource Border}" BorderThickness="1" CornerRadius="10" Padding="18">
        <Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions>
          <StackPanel><TextBlock FontSize="15" FontWeight="SemiBold" Text="Update-Ablauf"/><TextBlock Foreground="{StaticResource Muted}" FontSize="11" Margin="0,4,0,14" Text="Jeder Schritt wird einzeln geprüft."/></StackPanel>
          <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"><StackPanel x:Name="StepsPanel"/></ScrollViewer>
          <Border Grid.Row="2" Background="#12151A" BorderBrush="#272D37" BorderThickness="1" CornerRadius="8" Padding="12" Margin="0,14,0,0">
            <StackPanel><TextBlock Foreground="{StaticResource Muted}" FontSize="10" Text="SICHERHEIT"/>
              <TextBlock FontSize="11" Margin="0,5,0,0" TextWrapping="Wrap" Text="Kein Datenbank-Reset. Keine Uploads, Secrets oder /app/data-Dateien werden ersetzt."/>
            </StackPanel>
          </Border>
        </Grid>
      </Border>

      <Grid Grid.Column="2"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions>
        <Border Background="{StaticResource Panel}" BorderBrush="{StaticResource Border}" BorderThickness="1" CornerRadius="10" Padding="22">
          <Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions>
            <Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
              <StackPanel><TextBlock x:Name="PhaseText" FontSize="20" FontWeight="SemiBold" Text="Updater wird vorbereitet"/>
                <TextBlock x:Name="DetailText" Foreground="{StaticResource Muted}" Margin="0,7,20,0" TextWrapping="Wrap" Text="Die sichere Update-Umgebung wird initialisiert."/>
              </StackPanel>
              <Border x:Name="StatusBadge" Grid.Column="1" Background="#22314A" BorderBrush="#36598A" BorderThickness="1" CornerRadius="7" Padding="12,7" VerticalAlignment="Top">
                <TextBlock x:Name="StatusText" FontWeight="Bold" FontSize="11" Text="START"/>
              </Border>
            </Grid>
            <Grid Grid.Row="1" Margin="0,24,0,0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="64"/></Grid.ColumnDefinitions>
              <ProgressBar x:Name="ProgressBar" Height="10" Minimum="0" Maximum="100" Value="0" Foreground="{StaticResource Accent}" Background="#262C35" BorderThickness="0"/>
              <TextBlock x:Name="PercentText" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" FontWeight="SemiBold" Text="0 %"/>
            </Grid>
            <Grid Grid.Row="2" Margin="0,13,0,0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
              <TextBlock x:Name="ActivityText" Foreground="{StaticResource Muted}" FontSize="11" Text="Laufzeit 00:00"/>
              <TextBlock x:Name="HeartbeatText" Grid.Column="1" Foreground="{StaticResource Muted}" FontSize="11" Text="Status wird aufgebaut"/>
            </Grid>
            <Border x:Name="InputPanel" Grid.Row="3" Visibility="Collapsed" Background="#171E2A" BorderBrush="#35547E" BorderThickness="1" CornerRadius="8" Padding="15" Margin="0,18,0,0">
              <Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions>
                <TextBlock x:Name="InputTitle" FontWeight="SemiBold" Text="Eingabe erforderlich"/>
                <TextBlock x:Name="InputPrompt" Grid.Row="1" Foreground="{StaticResource Muted}" Margin="0,6,0,10" TextWrapping="Wrap"/>
                <Grid Grid.Row="2"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
                  <PasswordBox x:Name="SecretInput" Height="34" Padding="8" Background="#0F1217" Foreground="#EEF1F5" BorderBrush="#3A4657"/>
                  <Button x:Name="SubmitInputButton" Grid.Column="1" Style="{StaticResource PrimaryButton}" Margin="10,0,0,0" Content="Sicher übernehmen"/>
                </Grid>
              </Grid>
            </Border>
          </Grid>
        </Border>

        <Border Grid.Row="1" x:Name="ErrorPanel" Visibility="Collapsed" Background="#24181B" BorderBrush="#7A3640" BorderThickness="1" CornerRadius="10" Padding="18" Margin="0,14,0,0">
          <StackPanel><TextBlock x:Name="ErrorTitle" FontSize="15" FontWeight="SemiBold" Foreground="#FFB6BE" Text="Update gestoppt"/>
            <TextBlock x:Name="ErrorText" Margin="0,7,0,0" TextWrapping="Wrap"/>
            <TextBlock x:Name="RemediationText" Foreground="#D7A9AF" Margin="0,8,0,0" TextWrapping="Wrap"/>
          </StackPanel>
        </Border>

        <Border Grid.Row="2" Background="{StaticResource Panel}" BorderBrush="{StaticResource Border}" BorderThickness="1" CornerRadius="10" Margin="0,14,0,0">
          <Grid><Grid.RowDefinitions><RowDefinition Height="42"/><RowDefinition Height="*"/></Grid.RowDefinitions>
            <Grid Margin="16,0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
              <TextBlock VerticalAlignment="Center" FontWeight="SemiBold" Text="Technisches Protokoll"/>
              <TextBlock x:Name="LogPathText" Grid.Column="1" VerticalAlignment="Center" Foreground="{StaticResource Muted}" FontSize="10" Text="wird vorbereitet"/>
            </Grid>
            <TextBox x:Name="LogBox" Grid.Row="1" Margin="12,0,12,12" IsReadOnly="True" AcceptsReturn="True" TextWrapping="NoWrap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Background="#0D0F13" Foreground="#CDD4DE" BorderBrush="#292F38" FontFamily="Consolas" FontSize="11" Padding="10"/>
          </Grid>
        </Border>
      </Grid>
    </Grid>

    <Border Grid.Row="2" Background="#14171C" BorderBrush="#252B35" BorderThickness="0,1,0,0">
      <Grid Margin="24,0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
          <Button x:Name="OpenLogButton" Content="Protokoll öffnen" IsEnabled="False"/>
          <Button x:Name="OpenRuntimeButton" Content="Diagnoseordner" Margin="10,0,0,0" IsEnabled="False"/>
          <Button x:Name="CopyErrorButton" Content="Fehler kopieren" Margin="10,0,0,0" Visibility="Collapsed"/>
        </StackPanel>
        <StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
          <Button x:Name="CancelButton" Content="Update abbrechen"/>
          <Button x:Name="RetryButton" Content="Erneut versuchen" Margin="10,0,0,0" Visibility="Collapsed"/>
          <Button x:Name="CloseButton" Style="{StaticResource PrimaryButton}" Content="Schließen" Margin="10,0,0,0" IsEnabled="False"/>
        </StackPanel>
      </Grid>
    </Border>
  </Grid>
</Window>
'@

$reader = [System.Xml.XmlNodeReader]::new([xml]$xaml)
$window = [System.Windows.Markup.XamlReader]::Load($reader)
$names = @('StepsPanel','PhaseText','DetailText','StatusBadge','StatusText','ProgressBar','PercentText','ActivityText','HeartbeatText','InputPanel','InputTitle','InputPrompt','SecretInput','SubmitInputButton','ErrorPanel','ErrorTitle','ErrorText','RemediationText','LogBox','LogPathText','OpenLogButton','OpenRuntimeButton','CopyErrorButton','CancelButton','RetryButton','CloseButton')
foreach ($name in $names) { Set-Variable -Name $name -Value $window.FindName($name) -Scope Script }

$steps = @(
  @{id='package'; title='Paket prüfen'}, @{id='tools'; title='System prüfen'}, @{id='github'; title='GitHub verbinden'},
  @{id='production'; title='Zielzustand erkennen'}, @{id='workspace'; title='Payload sicher vorbereiten'}, @{id='tests'; title='Vollständig testen'},
  @{id='pullrequest'; title='Pull Request abgleichen'}, @{id='merge'; title='Finalen Head prüfen und mergen'}, @{id='deploy'; title='Coolify deployen'}, @{id='verify'; title='Produktion bestätigen'}
)
$script:StepControls = @{}
foreach ($step in $steps) {
  $border = New-Object System.Windows.Controls.Border
  $border.CornerRadius = [System.Windows.CornerRadius]::new(6); $border.Padding = [System.Windows.Thickness]::new(9,8,9,8); $border.Margin = [System.Windows.Thickness]::new(0,0,0,4); $border.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString('#171A20')
  $grid = New-Object System.Windows.Controls.Grid
  $c1=New-Object System.Windows.Controls.ColumnDefinition; $c1.Width=[System.Windows.GridLength]::new(28); $grid.ColumnDefinitions.Add($c1)
  $c2=New-Object System.Windows.Controls.ColumnDefinition; $c2.Width=[System.Windows.GridLength]::new(1,[System.Windows.GridUnitType]::Star); $grid.ColumnDefinitions.Add($c2)
  $icon=New-Object System.Windows.Controls.TextBlock; $icon.Text='○'; $icon.Foreground='#6E7886'; $icon.FontSize=16; $icon.VerticalAlignment='Center'
  $label=New-Object System.Windows.Controls.TextBlock; $label.Text=$step.title; $label.Foreground='#AAB3BF'; $label.VerticalAlignment='Center'; [System.Windows.Controls.Grid]::SetColumn($label,1)
  $grid.Children.Add($icon)|Out-Null; $grid.Children.Add($label)|Out-Null; $border.Child=$grid; $StepsPanel.Children.Add($border)|Out-Null
  $script:StepControls[$step.id]=@{Border=$border;Icon=$icon;Label=$label}
}

$script:Worker=$null; $script:Timer=$null; $script:Terminal=$false; $script:ClosingAllowed=$false; $script:LastStatusAt=Get-Date; $script:StartedAt=Get-Date
$script:StatusFile=''; $script:EventFile=''; $script:InputFile=''; $script:CancelFile=''; $script:SessionFile=Join-Path $SessionRoot "$TargetVersion.json"; $script:LogFile=''; $script:StdoutFile=''; $script:StderrFile=''; $script:EventOffset=0; $script:LastRequestId=''; $script:LastError=''

function Set-Badge([string]$state) {
  switch ($state) {
    'success' { $StatusText.Text='ERFOLGREICH'; $StatusBadge.Background='#173322'; $StatusBadge.BorderBrush='#2C7A4B'; $StatusText.Foreground='#8FE0AC' }
    'failed' { $StatusText.Text='GESTOPPT'; $StatusBadge.Background='#351B20'; $StatusBadge.BorderBrush='#8B3B48'; $StatusText.Foreground='#FFB6BE' }
    'input' { $StatusText.Text='EINGABE'; $StatusBadge.Background='#392E17'; $StatusBadge.BorderBrush='#8C6D27'; $StatusText.Foreground='#F4D47B' }
    'waiting' { $StatusText.Text='WARTE'; $StatusBadge.Background='#1B2D3B'; $StatusBadge.BorderBrush='#35627D'; $StatusText.Foreground='#91CBE9' }
    'cancelling' { $StatusText.Text='ABBRUCH'; $StatusBadge.Background='#392E17'; $StatusBadge.BorderBrush='#8C6D27'; $StatusText.Foreground='#F4D47B' }
    default { $StatusText.Text='LÄUFT'; $StatusBadge.Background='#1C2D49'; $StatusBadge.BorderBrush='#36598A'; $StatusText.Foreground='#9FC0FF' }
  }
}

function Update-Steps($status) {
  if (-not $status.steps) { return }
  foreach ($s in @($status.steps)) {
    if (-not $script:StepControls.ContainsKey([string]$s.id)) { continue }
    $c=$script:StepControls[[string]$s.id]
    switch ([string]$s.state) {
      'done' { $c.Icon.Text='●'; $c.Icon.Foreground='#62D28B'; $c.Label.Foreground='#EEF1F5'; $c.Border.Background='#18251E' }
      'active' { $c.Icon.Text='●'; $c.Icon.Foreground='#6EA1FF'; $c.Label.Foreground='#FFFFFF'; $c.Label.FontWeight='SemiBold'; $c.Border.Background='#1A2435' }
      'failed' { $c.Icon.Text='×'; $c.Icon.Foreground='#FF7A88'; $c.Label.Foreground='#FFD2D7'; $c.Border.Background='#2A191D' }
      'skipped' { $c.Icon.Text='–'; $c.Icon.Foreground='#77808D'; $c.Label.Foreground='#77808D'; $c.Border.Background='#171A20' }
      default { $c.Icon.Text='○'; $c.Icon.Foreground='#6E7886'; $c.Label.Foreground='#AAB3BF'; $c.Label.FontWeight='Normal'; $c.Border.Background='#171A20' }
    }
  }
}

function Write-InitialStatus {
  $steps=@(
    @{id='package';title='Paket prüfen';state='pending'},@{id='tools';title='System prüfen';state='pending'},@{id='github';title='GitHub verbinden';state='pending'},
    @{id='production';title='Zielzustand erkennen';state='pending'},@{id='workspace';title='Payload sicher vorbereiten';state='pending'},@{id='tests';title='Vollständig testen';state='pending'},
    @{id='pullrequest';title='Pull Request abgleichen';state='pending'},@{id='merge';title='Finalen Head prüfen und mergen';state='pending'},@{id='deploy';title='Coolify deployen';state='pending'},@{id='verify';title='Produktion bestätigen';state='pending'}
  )
  $payload=[ordered]@{version=$TargetVersion;updaterVersion=$UpdaterVersion;percent=0;phase='Updater wird vorbereitet';detail='Die überwachte Update-Umgebung wird initialisiert.';state='running';error='';remediation='';updatedAt=(Get-Date).ToString('o');logFile=$script:LogFile;sessionFile=$script:SessionFile;steps=$steps;request=$null}|ConvertTo-Json -Depth 8
  [IO.File]::WriteAllText($script:StatusFile,$payload,(New-Object Text.UTF8Encoding($false)))
}

function Get-WorkerExitDiagnostics {
  $parts=New-Object Collections.Generic.List[string]
  try {
    $stderr=[string]$script:Worker.StandardError.ReadToEnd()
    if($stderr){$stderr|Set-Content -LiteralPath $script:StderrFile -Encoding UTF8;$parts.Add("PowerShell-Fehlerkanal:`n$stderr")}
  } catch {}
  try {
    $stdout=[string]$script:Worker.StandardOutput.ReadToEnd()
    if($stdout){$stdout|Set-Content -LiteralPath $script:StdoutFile -Encoding UTF8;$parts.Add("PowerShell-Ausgabe:`n$stdout")}
  } catch {}
  if(Test-Path -LiteralPath $script:LogFile){
    try{
      $tail=@(Get-Content -LiteralPath $script:LogFile -Encoding UTF8 -Tail 35) -join [Environment]::NewLine
      if($tail){$parts.Add("Letzte Protokollzeilen:`n$tail")}
    }catch{}
  }
  if($parts.Count -eq 0){$parts.Add('Der Prozess lieferte keinen Fehlertext. Die Bootstrap-Dateien im Laufzeitordner wurden dennoch erhalten.')}
  return ($parts -join ([Environment]::NewLine+[Environment]::NewLine))
}

function Start-Worker {
  $stamp=Get-Date -Format 'yyyyMMdd-HHmmss-fff'; $run=Join-Path $RuntimeRoot $stamp; New-Item -ItemType Directory -Path $run -Force|Out-Null
  $script:StatusFile=Join-Path $run 'status.json'; $script:EventFile=Join-Path $run 'events.ndjson'; $script:InputFile=Join-Path $run 'input.json'; $script:CancelFile=Join-Path $run 'cancel.flag'
  $script:LogFile=Join-Path $run 'updater.log'; $script:StdoutFile=Join-Path $run 'worker.stdout.log'; $script:StderrFile=Join-Path $run 'worker.stderr.log'
  $script:EventOffset=0; $script:Terminal=$false; $script:ClosingAllowed=$false; $script:StartedAt=Get-Date; $script:LastStatusAt=Get-Date; $script:LastRequestId=''; $script:LastError=''
  $ErrorPanel.Visibility='Collapsed'; $InputPanel.Visibility='Collapsed'; $CopyErrorButton.Visibility='Collapsed'; $RetryButton.Visibility='Collapsed'; $CloseButton.IsEnabled=$false; $CancelButton.IsEnabled=$true; $OpenLogButton.IsEnabled=$true; $LogBox.Clear()
  $LogPathText.Text=[IO.Path]::GetFileName($script:LogFile)
  [IO.File]::WriteAllText($script:LogFile,"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff') [UI] Laufzeitordner angelegt: $run$([Environment]::NewLine)",(New-Object Text.UTF8Encoding($false)))
  $OpenRuntimeButton.IsEnabled=$true
  foreach($entry in $script:StepControls.Values){$entry.Icon.Text='○';$entry.Icon.Foreground='#6E7886';$entry.Label.Foreground='#AAB3BF';$entry.Label.FontWeight='Normal';$entry.Border.Background='#171A20'}
  Set-Badge 'running'; $PhaseText.Text='Updater wird vorbereitet'; $DetailText.Text='Die überwachte Update-Umgebung wird initialisiert.'; $ProgressBar.Value=0; $PercentText.Text='0 %'
  Write-InitialStatus

  $args=@('-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',('"{0}"' -f $WorkerHostScript),'-CoreScript',('"{0}"' -f $WorkerScript),'-StatusFile',('"{0}"' -f $script:StatusFile),'-EventFile',('"{0}"' -f $script:EventFile),'-InputFile',('"{0}"' -f $script:InputFile),'-CancelFile',('"{0}"' -f $script:CancelFile),'-SessionFile',('"{0}"' -f $script:SessionFile),'-LogFile',('"{0}"' -f $script:LogFile))
  if($SkipProductionDeploy){$args+='-SkipProductionDeploy'}
  $psi=New-Object Diagnostics.ProcessStartInfo
  $psi.FileName='powershell.exe'; $psi.Arguments=($args -join ' '); $psi.UseShellExecute=$false; $psi.CreateNoWindow=$true; $psi.WorkingDirectory=$PackageRoot
  $psi.RedirectStandardOutput=$true; $psi.RedirectStandardError=$true
  $script:Worker=New-Object Diagnostics.Process; $script:Worker.StartInfo=$psi
  if(-not $script:Worker.Start()){throw 'Der überwachte Update-Prozess konnte nicht gestartet werden.'}
}

function Read-NewEvents {
  if(-not (Test-Path -LiteralPath $script:EventFile)){return}
  $stream=[IO.File]::Open($script:EventFile,[IO.FileMode]::Open,[IO.FileAccess]::Read,[IO.FileShare]::ReadWrite)
  try {
    if($script:EventOffset -gt $stream.Length){$script:EventOffset=0}
    $stream.Seek($script:EventOffset,[IO.SeekOrigin]::Begin)|Out-Null
    $reader=New-Object IO.StreamReader($stream,[Text.Encoding]::UTF8,$true,4096,$true)
    while(-not $reader.EndOfStream){
      $line=$reader.ReadLine(); if(-not $line){continue}
      try{$e=$line|ConvertFrom-Json; $display=('{0}  {1,-7}  {2}' -f ([DateTime]::Parse($e.at).ToString('HH:mm:ss')),[string]$e.level,[string]$e.message)}catch{$display=$line}
      $LogBox.AppendText($display+[Environment]::NewLine); $LogBox.ScrollToEnd()
    }
    $script:EventOffset=$stream.Position; $reader.Dispose()
  } finally {$stream.Dispose()}
}

function Apply-Status($s) {
  $script:LastStatusAt=Get-Date
  $PhaseText.Text=[string]$s.phase; $DetailText.Text=[string]$s.detail
  $p=[Math]::Max(0,[Math]::Min(100,[int]$s.percent)); $ProgressBar.Value=$p; $PercentText.Text="$p %"
  Set-Badge ([string]$s.state); Update-Steps $s
  if($s.logFile){$script:LogFile=[string]$s.logFile;$LogPathText.Text=[IO.Path]::GetFileName($script:LogFile);$OpenLogButton.IsEnabled=$true}
  if([string]$s.state -eq 'input' -and $s.request){
    $requestId=[string]$s.request.id
    if($requestId -ne $script:LastRequestId){$script:LastRequestId=$requestId;$SecretInput.Clear();$InputTitle.Text=[string]$s.request.title;$InputPrompt.Text=[string]$s.request.prompt;$InputPanel.Visibility='Visible';$SecretInput.Focus()}
  } else {$InputPanel.Visibility='Collapsed'}
  if([string]$s.state -in @('success','failed','cancelled')){
    $script:Terminal=$true;$script:ClosingAllowed=$true;$CancelButton.IsEnabled=$false;$CloseButton.IsEnabled=$true
    if([string]$s.state -eq 'failed'){
      $script:LastError=[string]$s.error; $ErrorTitle.Text='Update sicher gestoppt';$ErrorText.Text=[string]$s.error;$RemediationText.Text=[string]$s.remediation;$ErrorPanel.Visibility='Visible';$CopyErrorButton.Visibility='Visible';$RetryButton.Visibility='Visible'
    } elseif([string]$s.state -eq 'cancelled'){
      $script:LastError='Das Update wurde durch den Benutzer abgebrochen.';$ErrorTitle.Text='Update abgebrochen';$ErrorText.Text=$script:LastError;$RemediationText.Text='Ein erneuter Start setzt den kontrollierten Ablauf fort.';$ErrorPanel.Visibility='Visible';$CopyErrorButton.Visibility='Visible';$RetryButton.Visibility='Visible'
    }
  }
}

$SubmitInputButton.Add_Click({
  $value=$SecretInput.Password.Trim(); if(-not $value){[System.Windows.MessageBox]::Show('Bitte einen Wert eintragen.','Vendoo Updater',[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Warning)|Out-Null;return}
  @{requestId=$script:LastRequestId;value=$value;submittedAt=(Get-Date).ToString('o')}|ConvertTo-Json|Set-Content -LiteralPath $script:InputFile -Encoding UTF8
  $SecretInput.Clear();$InputPanel.Visibility='Collapsed';$DetailText.Text='Eingabe wurde sicher übernommen und wird geprüft.'
})
$CancelButton.Add_Click({if($script:Worker -and -not $script:Worker.HasExited){New-Item -ItemType File -Path $script:CancelFile -Force|Out-Null;Set-Badge 'cancelling';$DetailText.Text='Der aktuelle Prozess wird kontrolliert beendet. Bitte kurz geöffnet lassen.';$CancelButton.IsEnabled=$false}})
$RetryButton.Add_Click({ try { Start-Worker } catch { $script:LastError=$_.Exception.Message; $ErrorText.Text=$script:LastError; $ErrorPanel.Visibility='Visible'; Set-Badge 'failed' } })
$CloseButton.Add_Click({$script:ClosingAllowed=$true;$window.Close()})
$OpenLogButton.Add_Click({if($script:LogFile -and (Test-Path -LiteralPath $script:LogFile)){Start-Process notepad.exe -ArgumentList ('"{0}"' -f $script:LogFile)}elseif($script:StatusFile){$folder=Split-Path -Parent $script:StatusFile;if(Test-Path $folder){Start-Process explorer.exe -ArgumentList ('"{0}"' -f $folder)}}})
$OpenRuntimeButton.Add_Click({if($script:StatusFile){$folder=Split-Path -Parent $script:StatusFile;if(Test-Path $folder){Start-Process explorer.exe -ArgumentList ('"{0}"' -f $folder)}}})
$CopyErrorButton.Add_Click({if($script:LastError){[System.Windows.Clipboard]::SetText($script:LastError+[Environment]::NewLine+[Environment]::NewLine+'Protokoll: '+$script:LogFile)}})
$window.Add_Closing({param($sender,$e) if(-not $script:ClosingAllowed){if($script:Worker -and -not $script:Worker.HasExited){$choice=[System.Windows.MessageBox]::Show('Das Update läuft noch. Soll es kontrolliert abgebrochen werden?','Vendoo Updater',[System.Windows.MessageBoxButton]::YesNo,[System.Windows.MessageBoxImage]::Warning);if($choice -eq [System.Windows.MessageBoxResult]::Yes){New-Item -ItemType File -Path $script:CancelFile -Force|Out-Null;$e.Cancel=$true;$CancelButton.IsEnabled=$false;$DetailText.Text='Abbruch wird ausgeführt …'}else{$e.Cancel=$true}}else{$e.Cancel=$true}}})

$script:Timer=New-Object System.Windows.Threading.DispatcherTimer
$script:Timer.Interval=[TimeSpan]::FromMilliseconds(350)
$script:Timer.Add_Tick({
  try {
    Read-NewEvents
    if(Test-Path -LiteralPath $script:StatusFile){try{$s=Get-Content -LiteralPath $script:StatusFile -Raw -Encoding UTF8|ConvertFrom-Json;Apply-Status $s}catch{}}
    $elapsed=(Get-Date)-$script:StartedAt;$idle=[int]((Get-Date)-$script:LastStatusAt).TotalSeconds
    $ActivityText.Text=('Laufzeit {0:00}:{1:00}' -f [int]$elapsed.TotalMinutes,$elapsed.Seconds);$HeartbeatText.Text=if($idle -lt 5){'Status aktuell'}else{"Letzte Meldung vor $idle Sek."}
    if($script:Worker -and $script:Worker.HasExited -and -not $script:Terminal){
      if(Test-Path -LiteralPath $script:StatusFile){
        try{$final=Get-Content -LiteralPath $script:StatusFile -Raw -Encoding UTF8|ConvertFrom-Json;Apply-Status $final}catch{}
      }
      if(-not $script:Terminal){
        $diagnostics=Get-WorkerExitDiagnostics
        $script:Terminal=$true;$script:ClosingAllowed=$true;$CancelButton.IsEnabled=$false;$CloseButton.IsEnabled=$true;$RetryButton.Visibility='Visible';$CopyErrorButton.Visibility='Visible';Set-Badge 'failed'
        $PhaseText.Text='Updater-Prozess unerwartet beendet';$DetailText.Text='Die vollständige Startdiagnose wurde aufgezeichnet. Das Fenster bleibt geöffnet.'
        $script:LastError="Der überwachte Worker-Host wurde mit Exit-Code $($script:Worker.ExitCode) beendet.`n`n$diagnostics"
        $ErrorText.Text=$script:LastError;$RemediationText.Text='Protokoll öffnen zeigt die vollständige Ausnahme mit Datei und Zeile. Danach kann derselbe sichere Lauf erneut gestartet werden.';$ErrorPanel.Visibility='Visible'
      }
    }
  } catch {
    $script:LastError=$_.Exception.Message
  }
})

try { Start-Worker; $script:Timer.Start(); $window.ShowDialog()|Out-Null }
finally { try{$script:Timer.Stop()}catch{};if($script:Worker -and -not $script:Worker.HasExited){try{New-Item -ItemType File -Path $script:CancelFile -Force|Out-Null}catch{}};try{$mutex.ReleaseMutex()}catch{};$mutex.Dispose() }
