param(
  [switch]$ForceKillPorts
)

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

$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$RuntimeDir = Join-Path $RepoRoot ".runtime"
$ManagedNames = @("api", "web")
$KnownPorts = @(3000, 3001, 3002)

function Write-Step([string]$Message) {
  Write-Host "==> $Message" -ForegroundColor Cyan
}

function Write-WarnLine([string]$Message) {
  Write-Host "WARN: $Message" -ForegroundColor Yellow
}

function Get-PidFilePath([string]$Name) {
  return Join-Path $RuntimeDir "$Name.pid"
}

function Test-ProcessRunning([int]$ProcessId) {
  try {
    $null = Get-Process -Id $ProcessId -ErrorAction Stop
    return $true
  } catch {
    return $false
  }
}

function Get-ProcessCommandLine([int]$ProcessId) {
  try {
    $process = Get-CimInstance Win32_Process -Filter "ProcessId = $ProcessId"
    if ($null -eq $process -or $null -eq $process.CommandLine) {
      return ""
    }
    return [string]$process.CommandLine
  } catch {
    return ""
  }
}

function Test-SentAIProcess([int]$ProcessId) {
  $commandLine = Get-ProcessCommandLine $ProcessId
  if (-not $commandLine) {
    return $false
  }

  return $commandLine -like "*SentAI*" -or
    $commandLine -like "*@sentai*" -or
    $commandLine -like "*npm.cmd run dev:api*" -or
    $commandLine -like "*npm.cmd run dev:web*"
}

function Stop-ProcessTree([int]$ProcessId) {
  & taskkill /PID $ProcessId /T /F | Out-Null
}

function Get-ListenerOwners([int]$Port) {
  try {
    return @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction Stop |
      Select-Object -ExpandProperty OwningProcess -Unique)
  } catch {
    return @()
  }
}

foreach ($name in $ManagedNames) {
  $pidFile = Get-PidFilePath $name
  if (-not (Test-Path $pidFile)) {
    continue
  }

  $raw = (Get-Content $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
  $managedPid = 0
  if ([int]::TryParse($raw, [ref]$managedPid) -and (Test-ProcessRunning $managedPid)) {
    Write-Step "Stopping managed $name process $managedPid."
    Stop-ProcessTree $managedPid
  }

  Remove-Item $pidFile -ErrorAction SilentlyContinue
}

foreach ($port in $KnownPorts) {
  [array]$owners = @(Get-ListenerOwners $port)
  foreach ($owner in $owners) {
    if ($ForceKillPorts -or (Test-SentAIProcess $owner)) {
      Write-WarnLine "Stopping remaining process $owner on port $port."
      Stop-ProcessTree $owner
      continue
    }

    Write-WarnLine "Port $port is still used by non-SentAI process $owner. Leaving it untouched."
  }
}

Start-Sleep -Seconds 2

Write-Host ""
foreach ($port in $KnownPorts) {
  [array]$owners = @(Get-ListenerOwners $port)
  if ($owners.Count -eq 0) {
    Write-Host "Port $port closed." -ForegroundColor Green
  } else {
    Write-Host "Port $port still in use by $($owners -join ', ')." -ForegroundColor Yellow
  }
}
