# Shipped as run-image.ps1.txt on purpose: Gmail blocks e-mails whose zip contains a .ps1 file.
# Claude copies it to run-image.ps1 at install time (or right before the first run) and runs that copy.
# clearly-image-commands: runs one image command through the Codex CLI (image generation on the ChatGPT plan, no API key).
# Usage (Claude Code runs this, not the user):
#   powershell -NoProfile -ExecutionPolicy Bypass -File run-image.ps1 -PromptFile <prompt.txt> -Command proshot -Target <file|folder> [-Orientation auto|square|landscape|portrait] [-OutDir <folder>] [-Max 20]
#   Text-only (no input photo): omit -Target and pass -OutDir.
# Output lines: OK <path> | MISSING <name> | LIMIT | ERROR <message>
param(
  [Parameter(Mandatory = $true)][string]$PromptFile,
  [Parameter(Mandatory = $true)][string]$Command,
  [string]$Target = "",
  [string]$Orientation = "auto",
  [string]$OutDir = "",
  [int]$Max = 20
)
$ErrorActionPreference = "Continue"
$OutputEncoding = New-Object System.Text.UTF8Encoding $false
try { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false } catch { }

if (-not (Get-Command codex -ErrorAction SilentlyContinue)) { "ERROR codex-not-installed"; exit 3 }
if (-not (Test-Path -LiteralPath $PromptFile)) { "ERROR prompt-file-missing $PromptFile"; exit 3 }
$userPrompt = Get-Content -Raw -Encoding UTF8 -LiteralPath $PromptFile
$Command = $Command.TrimStart('/').ToLower()

# Which photos?
$images = @()
if ($Target) {
  if (-not (Test-Path -LiteralPath $Target)) { "ERROR target-missing $Target"; exit 3 }
  $item = Get-Item -LiteralPath $Target
  if ($item.PSIsContainer) {
    $images = Get-ChildItem -LiteralPath $item.FullName -File |
      Where-Object { $_.Extension -match '^\.(jpe?g|png|webp)$' } |
      Sort-Object Name
    if (-not $OutDir) { $OutDir = Join-Path $item.FullName "clearly-output" }
  } else {
    $images = @($item)
    if (-not $OutDir) { $OutDir = Join-Path $item.DirectoryName "clearly-output" }
  }
  if ($images.Count -eq 0) { "ERROR no-images-in-folder"; exit 3 }
  if ($images.Count -gt $Max) { "ERROR too-many-images $($images.Count) (max $Max)"; exit 3 }
} elseif (-not $OutDir) { $OutDir = (Get-Location).Path }

New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$OutDir = (Resolve-Path -LiteralPath $OutDir).Path
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME ".codex" }
$cache = Join-Path $codexHome "generated_images"

$orient = switch ($Orientation) {
  "square"    { "square 1024x1024" }
  "landscape" { "landscape 1536x1024" }
  "portrait"  { "portrait 1024x1536" }
  default     { "match the attached photo: the closest of square 1024x1024, landscape 1536x1024 or portrait 1024x1536" }
}

function Get-FreeName([string]$base) {
  $n = "$base-$Command.png"; $i = 2
  while (Test-Path -LiteralPath (Join-Path $OutDir $n)) { $n = "$base-$Command-v$i.png"; $i++ }
  return $n
}

function Invoke-One([string]$name, [string]$imagePath) {
  $verb = if ($imagePath) { "EDIT the attached reference photo: create ONE new image based on it" } else { "create ONE image" }
  $instruction = @"
Use your built-in image generation tool (`$imagegen) to $verb and save it into
the current working directory as ``$name``. Do NOT write code, do NOT ask questions,
do NOT run other tools. Just generate, save, and reply with the full absolute file path.

Orientation: $orient. Quality: high.

Visual description:
$userPrompt
"@
  $log = Join-Path $env:TEMP ("clearly-codex-" + [guid]::NewGuid().ToString("N") + ".jsonl")
  $start = Get-Date
  if ($imagePath) {
    $instruction | codex exec --json -s workspace-write --skip-git-repo-check --cd $OutDir -i $imagePath *> $log
  } else {
    $instruction | codex exec --json -s workspace-write --skip-git-repo-check --cd $OutDir *> $log
  }
  $txt = Get-Content -Raw -Encoding UTF8 -LiteralPath $log -ErrorAction SilentlyContinue
  Remove-Item -LiteralPath $log -ErrorAction SilentlyContinue
  if ($txt -match '(?i)usage limit|usage_limit') { return "LIMIT" }
  $dest = Join-Path $OutDir $name
  if ((Test-Path -LiteralPath $dest) -and (Get-Item -LiteralPath $dest).LastWriteTime -ge $start) { return "OK $dest" }
  # Codex sometimes reports a path without copying the file: take it from this session's own cache folder only.
  if ($txt -match '"thread_id"\s*:\s*"([0-9a-fA-F-]+)"') {
    $folder = Join-Path $cache $Matches[1]
    if (Test-Path -LiteralPath $folder) {
      $f = Get-ChildItem -LiteralPath $folder -Recurse -File |
        Where-Object { $_.Extension -match '^\.(png|jpe?g|webp)$' -and $_.LastWriteTime -ge $start } |
        Sort-Object LastWriteTime -Descending | Select-Object -First 1
      if ($f) { Copy-Item -LiteralPath $f.FullName -Destination $dest -Force; return "OK $dest" }
    }
  }
  if ($txt -match '(?i)not logged in|unauthorized|sign in again') { return "ERROR codex-login" }
  return "MISSING $name"
}

if ($images.Count -eq 0) {
  $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
  Invoke-One (Get-FreeName "image-$stamp") ""
  exit 0
}
$n = 0
foreach ($img in $images) {
  $n++
  Write-Output "... $n/$($images.Count) $($img.Name)"
  $r = Invoke-One (Get-FreeName $img.BaseName) $img.FullName
  Write-Output $r
  if ($r -eq "LIMIT") { Write-Output "STOPPED after $($n-1) of $($images.Count)"; exit 2 }
}
Write-Output "DONE $OutDir"
