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

    [string]$EnrollmentToken = "",

    [string]$Name = $env:COMPUTERNAME,
    [string]$TaskName = "RemoteDevops Agent",
    [string]$ConfigPath = "$env:LOCALAPPDATA\RemoteDevops\agent.json",
    [string]$ProjectRoot = (Resolve-Path "$PSScriptRoot\..").Path,
    [string]$Python = "",
    [string]$AgentExe = "",
    [switch]$UseExistingConfig
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function ConvertTo-JsonString {
    param([string]$Value)

    if ($null -eq $Value) {
        $Value = ""
    }

    $builder = New-Object System.Text.StringBuilder
    foreach ($character in $Value.ToCharArray()) {
        $code = [int][char]$character
        if ($character -eq '"') {
            [void]$builder.Append('\"')
        } elseif ($character -eq '\') {
            [void]$builder.Append('\\')
        } elseif ($character -eq [char]8) {
            [void]$builder.Append('\b')
        } elseif ($character -eq [char]9) {
            [void]$builder.Append('\t')
        } elseif ($character -eq [char]10) {
            [void]$builder.Append('\n')
        } elseif ($character -eq [char]12) {
            [void]$builder.Append('\f')
        } elseif ($character -eq [char]13) {
            [void]$builder.Append('\r')
        } elseif ($code -lt 32) {
            [void]$builder.Append(('\u{0:x4}' -f $code))
        } else {
            [void]$builder.Append($character)
        }
    }

    '"' + $builder.ToString() + '"'
}

function Write-AgentConfig {
    param(
        [string]$Path,
        [string]$ServerValue,
        [string]$TokenValue,
        [string]$NameValue
    )

    $entries = @()
    $entries += "  `"server`": $(ConvertTo-JsonString $ServerValue)"
    if ($TokenValue) {
        $entries += "  `"token`": $(ConvertTo-JsonString $TokenValue)"
        $entries += "  `"token_type`": `"enrollment`""
    }
    $entries += "  `"name`": $(ConvertTo-JsonString $NameValue)"

    $jsonLines = @("{")
    for ($index = 0; $index -lt $entries.Count; $index++) {
        $line = $entries[$index]
        if ($index -lt ($entries.Count - 1)) {
            $line = "$line,"
        }
        $jsonLines += $line
    }
    $jsonLines += "}"
    $json = [string]::Join("`r`n", $jsonLines)
    $encoding = New-Object System.Text.UTF8Encoding $false
    [System.IO.File]::WriteAllText($Path, $json, $encoding)
}

function Test-IsCurrentProcessAdmin {
    $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object System.Security.Principal.WindowsPrincipal($identity)
    return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Install-StartupFallback {
    param(
        [string]$TaskNameValue,
        [string]$RunnerPathValue,
        [string]$WorkingDirectoryValue
    )

    $startupDirectory = [Environment]::GetFolderPath("Startup")
    if (-not $startupDirectory) {
        throw "Startup folder was not found for the current user."
    }
    $startupCommand = Join-Path $startupDirectory "$TaskNameValue.cmd"
    $startupLines = @(
        "@echo off",
        "cd /d `"$WorkingDirectoryValue`"",
        "call `"$RunnerPathValue`""
    )
    [System.IO.File]::WriteAllText($startupCommand, [string]::Join("`r`n", $startupLines), [System.Text.Encoding]::ASCII)
    Start-Process -FilePath "cmd.exe" -ArgumentList @("/c", "`"$RunnerPathValue`"") -WorkingDirectory $WorkingDirectoryValue -WindowStyle Hidden
    Write-Host "Installed Startup fallback: $startupCommand"
}

if (-not $AgentExe -and -not $Python) {
    $pythonCommand = Get-Command python -ErrorAction SilentlyContinue
    if (-not $pythonCommand) {
        throw "python.exe was not found. Pass -Python or build and pass -AgentExe."
    }
    $Python = $pythonCommand.Source
}

$configDirectory = Split-Path -Parent $ConfigPath
New-Item -ItemType Directory -Path $configDirectory -Force | Out-Null

if ($UseExistingConfig) {
    if (-not (Test-Path $ConfigPath)) {
        throw "Existing config was not found: $ConfigPath"
    }
} else {
    Write-AgentConfig `
        -Path $ConfigPath `
        -ServerValue $Server `
        -TokenValue $EnrollmentToken `
        -NameValue $Name
}

$currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name

if ($AgentExe) {
    $execute = (Resolve-Path $AgentExe).Path
    $arguments = "--config `"$ConfigPath`""
    $workingDirectory = Split-Path -Parent $execute
} else {
    $execute = $Python
    $arguments = "-m remote_admin.agent.windows_agent --config `"$ConfigPath`""
    $workingDirectory = $ProjectRoot
}

$runnerPath = Join-Path $configDirectory "run-agent.cmd"
$logPath = Join-Path $configDirectory "agent-run.log"
$runnerLines = @(
    "@echo off",
    "cd /d `"$workingDirectory`"",
    "`"$execute`" $arguments >> `"$logPath`" 2>&1"
)
[System.IO.File]::WriteAllText($runnerPath, [string]::Join("`r`n", $runnerLines), [System.Text.Encoding]::ASCII)

$installed = $false
$isAdmin = Test-IsCurrentProcessAdmin

if (Get-Command New-ScheduledTaskAction -ErrorAction SilentlyContinue) {
    try {
        $action = New-ScheduledTaskAction `
            -Execute $runnerPath `
            -WorkingDirectory $configDirectory

        $trigger = New-ScheduledTaskTrigger -AtLogOn
        $runLevel = if ($isAdmin) { "Highest" } else { "Limited" }
        $principal = New-ScheduledTaskPrincipal `
            -UserId $currentIdentity `
            -LogonType Interactive `
            -RunLevel $runLevel

        $settings = New-ScheduledTaskSettingsSet `
            -AllowStartIfOnBatteries `
            -DontStopIfGoingOnBatteries `
            -RestartCount 999 `
            -RestartInterval (New-TimeSpan -Minutes 1)

        Register-ScheduledTask `
            -TaskName $TaskName `
            -Action $action `
            -Trigger $trigger `
            -Principal $principal `
            -Settings $settings `
            -Force | Out-Null

        Start-ScheduledTask -TaskName $TaskName
        $installed = $true
        Write-Host "Installed scheduled task '$TaskName' for $currentIdentity"
    } catch {
        Write-Host "Scheduled Task install failed: $($_.Exception.Message)"
    }
}

if (-not $installed) {
    $taskCommand = "`"$runnerPath`""
    $runLevel = if ($isAdmin) { "HIGHEST" } else { "LIMITED" }
    schtasks.exe /Create /TN $TaskName /TR $taskCommand /SC ONLOGON /RU $currentIdentity /RL $runLevel /IT /F 1>$null 2>$null
    if ($LASTEXITCODE -eq 0) {
        schtasks.exe /Run /TN $TaskName 1>$null 2>$null
        $installed = $true
        Write-Host "Installed scheduled task '$TaskName' for $currentIdentity"
    } else {
        Install-StartupFallback -TaskNameValue $TaskName -RunnerPathValue $runnerPath -WorkingDirectoryValue $configDirectory
        $installed = $true
    }
}

Write-Host "Config: $ConfigPath"
Write-Host "Log: $logPath"
Write-Host "Run as boundary: commands execute as $currentIdentity"
