param(
  [int]$StartupTimeoutSeconds = 180,
  [ValidateSet('auto','fast','balanced','lowvram')]
  [string]$Profile = 'auto'
)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0

$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if ((Split-Path -Leaf $ScriptDir) -eq 'local-ai') {
  $VendooDir = Split-Path -Parent $ScriptDir
} else {
  $VendooDir = Split-Path -Parent $ScriptDir
}
$LocalAiDir = Join-Path $VendooDir 'local-ai'
$PortableRoot = Join-Path $LocalAiDir 'comfyui\ComfyUI_windows_portable'
$Python = Join-Path $PortableRoot 'python_embeded\python.exe'
$Main = Join-Path $PortableRoot 'ComfyUI\main.py'
$LogDir = Join-Path $VendooDir 'logs'
$StdoutLog = Join-Path $LogDir 'local-flux-runtime.log'
$StderrLog = Join-Path $LogDir 'local-flux-runtime-error.log'
$StateFile = Join-Path $LogDir 'local-flux-runtime-state.json'
$PidFile = Join-Path $LogDir 'local-flux-runtime.pid'
$ComfyUrl = 'http://127.0.0.1:8188'
$ComfyPort = 8188

New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
$env:PYTHONUTF8 = '1'
$env:PYTHONIOENCODING = 'utf-8'
$env:NO_COLOR = '1'

function Write-Utf8NoBom([string]$Path, [string]$Content) {
  $encoding = New-Object System.Text.UTF8Encoding($false)
  [System.IO.File]::WriteAllText($Path, $Content, $encoding)
}

function Remove-Ansi([string]$Text) {
  if ([string]::IsNullOrEmpty($Text)) { return '' }
  $pattern = ([string][char]27) + '\\[[0-?]*[ -/]*[@-~]'
  return [regex]::Replace($Text, $pattern, '')
}

function Read-Tail([string]$Path, [int]$Count = 16) {
  if (-not (Test-Path -LiteralPath $Path)) { return @() }
  try {
    return @(Get-Content -LiteralPath $Path -Tail $Count -ErrorAction SilentlyContinue | ForEach-Object { Remove-Ansi ([string]$_) })
  } catch { return @() }
}

function Save-RuntimeState([string]$Status, [string]$Message, [int]$ProcessId = 0, [int]$Elapsed = 0, [string]$ErrorMessage = '') {
  $state = [ordered]@{
    status = $Status
    message = $Message
    pid = if ($ProcessId -gt 0) { $ProcessId } else { $null }
    port = $ComfyPort
    url = $ComfyUrl
    elapsed_seconds = $Elapsed
    updated_at = (Get-Date).ToString('o')
    stdout_log = $StdoutLog
    stderr_log = $StderrLog
    error = $ErrorMessage
    stdout_tail = @(Read-Tail $StdoutLog 12)
    stderr_tail = @(Read-Tail $StderrLog 16)
  }
  Write-Utf8NoBom -Path $StateFile -Content ($state | ConvertTo-Json -Depth 5)
  if ($ProcessId -gt 0) { Write-Utf8NoBom -Path $PidFile -Content ([string]$ProcessId) }
}


function Test-ComfyFlag([string]$Flag) {
  try {
    $help = & $Python -s $Main --help 2>&1 | Out-String
    return $help -match [regex]::Escape($Flag)
  } catch { return $false }
}

function Get-NvidiaVramGb {
  try {
    $line = & nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>$null | Select-Object -First 1
    if ($line -match '^\s*(\d+)') { return [math]::Round(([double]$Matches[1] / 1024), 1) }
  } catch {}
  return 0
}

function Get-PerformanceArguments([string]$RequestedProfile) {
  $effective = $RequestedProfile
  $vramGb = Get-NvidiaVramGb
  if ($effective -eq 'auto') {
    if ($vramGb -ge 12) { $effective = 'fast' }
    elseif ($vramGb -gt 0 -and $vramGb -lt 8) { $effective = 'lowvram' }
    else { $effective = 'balanced' }
  }
  $flags = New-Object System.Collections.Generic.List[string]
  if ($effective -eq 'fast') {
    $flags.Add('--highvram')
    $flags.Add('--cache-classic')
    if (Test-ComfyFlag '--fast') {
      $flags.Add('--fast'); $flags.Add('fp16_accumulation'); $flags.Add('cublas_ops')
    }
  } elseif ($effective -eq 'lowvram') {
    $flags.Add('--lowvram')
    $flags.Add('--cache-none')
  } else {
    $flags.Add('--cache-classic')
  }
  return [pscustomobject]@{ profile = $effective; requested = $RequestedProfile; vram_gb = $vramGb; flags = @($flags) }
}

function Test-ComfyReady {
  try {
    $response = Invoke-WebRequest -UseBasicParsing -Uri "$ComfyUrl/system_stats" -TimeoutSec 4
    return $response.StatusCode -ge 200 -and $response.StatusCode -lt 300
  } catch { return $false }
}

function Get-ComfyProcess {
  try {
    $items = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
      $_.CommandLine -and
      $_.CommandLine -match 'ComfyUI[\\/]main\.py' -and
      $_.CommandLine -match "--port\s+$ComfyPort"
    } | Select-Object -First 1)
    if ($items.Count -gt 0) { return $items[0] }
    return $null
  } catch { return $null }
}

try {
  if (-not (Test-Path -LiteralPath $Python)) { throw "Embedded Python wurde nicht gefunden: $Python" }
  if (-not (Test-Path -LiteralPath $Main)) { throw "ComfyUI main.py wurde nicht gefunden: $Main" }

  if (Test-ComfyReady) {
    $existingReady = Get-ComfyProcess
    $readyPid = if ($existingReady) { [int]$existingReady.ProcessId } else { 0 }
    Save-RuntimeState 'ready' 'FLUX / ComfyUI ist bereits aktiv und erreichbar.' $readyPid 0
    exit 0
  }

  $existing = Get-ComfyProcess
  $comfyPid = 0
  $process = $null
  if ($existing) {
    $comfyPid = [int]$existing.ProcessId
    Save-RuntimeState 'starting' 'Ein vorhandener ComfyUI-Prozess initialisiert noch.' $comfyPid 0
  } else {
    Remove-Item -LiteralPath $StdoutLog,$StderrLog -Force -ErrorAction SilentlyContinue
    $performance = Get-PerformanceArguments $Profile
    $arguments = @(
      '-s', $Main,
      '--listen', '127.0.0.1',
      '--port', [string]$ComfyPort,
      '--disable-auto-launch',
      '--preview-method', 'none',
      '--windows-standalone-build',
      '--disable-all-custom-nodes',
      '--log-stdout',
      '--verbose', 'INFO'
    )
    foreach ($flag in $performance.flags) { $arguments += $flag }
    $process = Start-Process -FilePath $Python -ArgumentList $arguments -WorkingDirectory $PortableRoot -WindowStyle Hidden -RedirectStandardOutput $StdoutLog -RedirectStandardError $StderrLog -PassThru
    if (-not $process) { throw 'Der ComfyUI-Prozess konnte nicht gestartet werden.' }
    $comfyPid = [int]$process.Id
    Save-RuntimeState 'starting' ("FLUX / ComfyUI wird initialisiert · Profil: {0} · VRAM: {1} GB." -f $performance.profile, $performance.vram_gb) $comfyPid 0
  }

  $startedAt = Get-Date
  while (((Get-Date) - $startedAt).TotalSeconds -lt $StartupTimeoutSeconds) {
    Start-Sleep -Seconds 2
    $elapsed = [int][math]::Round(((Get-Date) - $startedAt).TotalSeconds)

    if (Test-ComfyReady) {
      Save-RuntimeState 'ready' "FLUX / ComfyUI ist nach ${elapsed}s erreichbar." $comfyPid $elapsed
      exit 0
    }

    $alive = $false
    try { $alive = $null -ne (Get-Process -Id $comfyPid -ErrorAction SilentlyContinue) } catch {}
    if (-not $alive) {
      $stderrTail = (Read-Tail $StderrLog 24) -join "`n"
      $stdoutTail = (Read-Tail $StdoutLog 24) -join "`n"
      $detail = if ($stderrTail) { $stderrTail } elseif ($stdoutTail) { $stdoutTail } else { 'Der Prozess wurde ohne verwertbare Ausgabe beendet.' }
      Save-RuntimeState 'failed' 'ComfyUI wurde während des Starts beendet.' $comfyPid $elapsed $detail
      throw "ComfyUI wurde während des Starts beendet. $detail"
    }

    $tail = @((Read-Tail $StdoutLog 3) + (Read-Tail $StderrLog 3)) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
    $lastLine = if ($tail.Count -gt 0) { [string]$tail[-1] } else { 'ComfyUI initialisiert Python, Datenbank und Modelle.' }
    Save-RuntimeState 'starting' "Start läuft seit ${elapsed}s: $lastLine" $comfyPid $elapsed
  }

  $timeoutDetail = @((Read-Tail $StderrLog 24) + (Read-Tail $StdoutLog 24)) -join "`n"
  Stop-Process -Id $comfyPid -Force -ErrorAction SilentlyContinue
  Save-RuntimeState 'failed' "ComfyUI war nach ${StartupTimeoutSeconds}s noch nicht erreichbar und wurde beendet." $comfyPid $StartupTimeoutSeconds $timeoutDetail
  throw "ComfyUI war nach ${StartupTimeoutSeconds}s noch nicht erreichbar und wurde beendet. Prüfe $StderrLog und $StdoutLog."
} catch {
  $message = Remove-Ansi ([string]$_.Exception.Message)
  $currentPid = 0
  try { if (Test-Path -LiteralPath $PidFile) { $currentPid = [int](Get-Content -LiteralPath $PidFile -Raw).Trim() } } catch {}
  $elapsed = 0
  try {
    if (Test-Path -LiteralPath $StateFile) {
      $oldState = Get-Content -LiteralPath $StateFile -Raw | ConvertFrom-Json
      $elapsed = [int]$oldState.elapsed_seconds
    }
  } catch {}
  Save-RuntimeState 'failed' 'FLUX / ComfyUI konnte nicht gestartet werden.' $currentPid $elapsed $message
  Write-Error $message
  exit 1
}
