[CmdletBinding()]
param(
    [string]$ProjectRoot = '',
    [string]$PhpExe = 'C:\php\php.exe',
    [switch]$RunNow,
    [switch]$ValidateOnly,
    [string]$TaskNamePrefix = 'Network Customers'
)

$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
    $ProjectRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
}
$ProjectRoot = [IO.Path]::GetFullPath($ProjectRoot)
$PhpExe = [IO.Path]::GetFullPath($PhpExe)
$worker = Join-Path $ProjectRoot 'admin\cron\background_worker.php'
if (-not (Test-Path -LiteralPath $PhpExe -PathType Leaf)) { throw "PHP executable not found: $PhpExe" }
if (-not (Test-Path -LiteralPath $worker -PathType Leaf)) { throw "Background worker not found: $worker" }
if ($TaskNamePrefix -notmatch '^[A-Za-z0-9 _.-]{3,80}$') { throw 'Invalid scheduled-task prefix.' }

$reportDir = Join-Path ([Environment]::GetFolderPath('CommonApplicationData')) 'NetworkCustomers'
New-Item -ItemType Directory -Path $reportDir -Force | Out-Null
$logPath = Join-Path $reportDir 'background-task-install.log'
function Write-TaskLog([string]$Message) {
    Add-Content -LiteralPath $logPath -Encoding UTF8 -Value (
        (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + '  ' + $Message
    )
}

$jobs = @(
    [pscustomobject]@{ Suffix = 'Monitor';          Job = 'monitor';          Minutes = 1 },
    [pscustomobject]@{ Suffix = 'PPP Cache';        Job = 'ppp-cache';        Minutes = 1 },
    [pscustomobject]@{ Suffix = 'Subscriber Queue'; Job = 'subscriber-queue'; Minutes = 1 },
    [pscustomobject]@{ Suffix = 'Automation';       Job = 'automation';       Minutes = 5 },
    [pscustomobject]@{ Suffix = 'Receiver Match';   Job = 'receiver-match';   Minutes = 5 },
    [pscustomobject]@{ Suffix = 'Backup';           Job = 'backup';           Minutes = 60 }
)
$jobs | ForEach-Object { Add-Member -InputObject $_ -NotePropertyName Task -NotePropertyValue ($TaskNamePrefix + ' ' + $_.Suffix) }

function Remove-ManagedTask([string]$TaskName) {
    $existing = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
    if ($null -eq $existing) { return }
    Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction Stop
    for ($attempt = 0; $attempt -lt 30; $attempt++) {
        if ($null -eq (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue)) { return }
        Start-Sleep -Milliseconds 100
    }
    throw "Windows did not release the previous scheduled task: $TaskName"
}

function Register-ManagedTask($Item) {
    $taskName = [string]$Item.Task
    Write-TaskLog "Preparing task: $taskName"
    if (-not $ValidateOnly) { Remove-ManagedTask $taskName }

    try {
        # Do not set WorkingDirectory on the action: older Windows Task Scheduler
        # implementations can reject that property with E_FAIL (0x80004005).
        $action = New-ScheduledTaskAction `
            -Execute $PhpExe `
            -Argument ('"{0}" {1}' -f $worker, $Item.Job)
        $trigger = New-ScheduledTaskTrigger `
            -Once `
            -At (Get-Date).AddMinutes(1) `
            -RepetitionInterval (New-TimeSpan -Minutes $Item.Minutes)
        $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
        $settings = New-ScheduledTaskSettingsSet `
            -StartWhenAvailable `
            -MultipleInstances IgnoreNew `
            -ExecutionTimeLimit (New-TimeSpan -Minutes 20)
        $definition = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -Settings $settings
        if ($ValidateOnly) {
            Write-TaskLog "Definition validated without registration: $taskName"
            return [pscustomobject]@{ TaskName=$taskName; State='DefinitionValid'; TaskPath='\\' }
        }
        Register-ScheduledTask -TaskName $taskName -InputObject $definition -Force -ErrorAction Stop | Out-Null
        Write-TaskLog "Registered through ScheduledTasks module: $taskName"
    } catch {
        $primaryError = $_.Exception.Message
        Write-TaskLog "ScheduledTasks module failed for ${taskName}: $primaryError"
        Remove-ManagedTask $taskName

        $schtasks = Join-Path $env:SystemRoot 'System32\schtasks.exe'
        if (-not (Test-Path -LiteralPath $schtasks -PathType Leaf)) {
            throw "Task registration failed and schtasks.exe is unavailable. Primary error: $primaryError"
        }
        $taskCommand = ('"{0}" "{1}" {2}' -f $PhpExe, $worker, $Item.Job)
        $fallbackOutput = & $schtasks /Create /TN $taskName /TR $taskCommand /SC MINUTE /MO ([string]$Item.Minutes) /RU SYSTEM /RL HIGHEST /F 2>&1
        if ($LASTEXITCODE -ne 0) {
            $fallbackText = ($fallbackOutput | Out-String).Trim()
            Write-TaskLog "schtasks fallback failed for $taskName ($LASTEXITCODE): $fallbackText"
            throw "Background task installation failed: $taskName. ScheduledTasks: $primaryError; schtasks: $fallbackText"
        }
        Write-TaskLog "Registered through schtasks fallback: $taskName"
    }

    $installed = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
    if ($null -eq $installed) { throw "Background task verification failed: $taskName" }
    Write-TaskLog "Verified task: $taskName"
    return $installed
}

Write-TaskLog "==== background task installation started; prefix=$TaskNamePrefix ===="
$installed = foreach ($item in $jobs) { Register-ManagedTask $item }
if (@($installed).Count -ne $jobs.Count) {
    throw "Background task verification failed: expected $($jobs.Count), found $(@($installed).Count)."
}

$report = $installed | Sort-Object TaskName | Select-Object TaskName, State, TaskPath
$reportPath = if ($ValidateOnly) { 'background-tasks-validation.json' } else { 'background-tasks.json' }
$report | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $reportDir $reportPath) -Encoding UTF8
if ($RunNow -and -not $ValidateOnly) {
    foreach ($item in $jobs) { Start-ScheduledTask -TaskName $item.Task -ErrorAction Stop }
}
Write-TaskLog "All $($jobs.Count) background tasks were installed and verified."
$report
