param(
    [Parameter(Mandatory = $true)]
    [string]$TaskFile,

    [string]$OutDir = "run_out",

    [switch]$Elevate,

    [switch]$UseSudo
)

$ErrorActionPreference = "Stop"

function Ensure-Dir {
    param([string]$Path)
    if (-not (Test-Path $Path)) {
        New-Item -ItemType Directory -Path $Path | Out-Null
    }
}

function Is-Admin {
    $id = [Security.Principal.WindowsIdentity]::GetCurrent()
    $p = New-Object Security.Principal.WindowsPrincipal($id)
    return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Request-Elevation {
    param([string]$ScriptPath, [string]$Args)
    Start-Process -FilePath "powershell" -ArgumentList "-ExecutionPolicy Bypass -File `"$ScriptPath`" $Args" -Verb RunAs
}

function Read-Tasks {
    param([string]$Path)
    if (-not (Test-Path $Path)) {
        throw "Task file not found: $Path"
    }
    $lines = Get-Content -Path $Path -ErrorAction Stop
    return $lines | Where-Object { $_ -and -not $_.StartsWith("#") }
}

Ensure-Dir $OutDir
$logPath = Join-Path $OutDir "run.log"

if ($Elevate -and -not (Is-Admin)) {
    $argList = "-TaskFile `"$TaskFile`" -OutDir `"$OutDir`""
    if ($UseSudo) { $argList += " -UseSudo" }
    Request-Elevation -ScriptPath $MyInvocation.MyCommand.Path -Args $argList
    Write-Host "[info] elevation requested, exiting current session"
    exit 0
}

$tasks = Read-Tasks -Path $TaskFile
if (-not $tasks -or $tasks.Count -eq 0) {
    "No tasks to run." | Set-Content -Path $logPath -Encoding UTF8
    Write-Host "[warn] no tasks found"
    exit 0
}

"Run started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" | Set-Content -Path $logPath -Encoding UTF8

foreach ($t in $tasks) {
    $cmd = $t.Trim()
    if (-not $cmd) { continue }

    if ($UseSudo -and (Get-Command "sudo" -ErrorAction SilentlyContinue)) {
        $cmd = "sudo $cmd"
    }

    Add-Content -Path $logPath -Value ("`n>>> " + $cmd)

    try {
        # Execute external input directly (eval-like behavior).
        $output = Invoke-Expression $cmd 2>&1
        if ($output) {
            Add-Content -Path $logPath -Value ($output | Out-String)
        }
        Add-Content -Path $logPath -Value "[ok]"
    }
    catch {
        Add-Content -Path $logPath -Value ("[error] " + $_.Exception.Message)
    }
}

Write-Host ("[ok] log written to {0}" -f $logPath)
