[CmdletBinding()]
param(
  [ValidateSet("AppOnly", "AppAndSettings", "Everything")]
  [string]$Mode = "AppOnly",
  [switch]$Quiet
)

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

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$manifestPath = Join-Path $scriptDir "atlas-app.json"

if (-not (Test-Path -LiteralPath $manifestPath)) {
  throw "atlas-app.json was not found next to uninstall.ps1"
}

$manifest = Get-Content -LiteralPath $manifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
$appName = [string]$manifest.appName
$exeName = [string]$manifest.exeName
$startMenuFolder = if ($manifest.startMenuFolder) { [string]$manifest.startMenuFolder } else { "Toonetic ATLAS" }

function Expand-AtlasPath([string]$Path) {
  if ([string]::IsNullOrWhiteSpace($Path)) { return $Path }
  return [Environment]::ExpandEnvironmentVariables($Path)
}

function Remove-AtlasFile([string]$Path) {
  $resolved = Expand-AtlasPath $Path
  if ($resolved -and (Test-Path -LiteralPath $resolved)) {
    Remove-Item -LiteralPath $resolved -Force -ErrorAction SilentlyContinue
  }
}

function Remove-AtlasDirectory([string]$Path) {
  $resolved = Expand-AtlasPath $Path
  if ($resolved -and (Test-Path -LiteralPath $resolved)) {
    Remove-Item -LiteralPath $resolved -Recurse -Force -ErrorAction SilentlyContinue
  }
}

function Confirm-Atlas([string]$Message) {
  if ($Quiet) { return $true }
  $answer = Read-Host "$Message [y/N]"
  return $answer -match '^(y|yes)$'
}

function Stop-AtlasProcesses {
  $names = @()
  if ($manifest.processNames) { $names += @($manifest.processNames) }
  if ($exeName) { $names += [System.IO.Path]::GetFileNameWithoutExtension($exeName) }
  $names = $names | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
  foreach ($name in $names) {
    Get-Process -Name $name -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
  }
}

function Remove-AtlasShortcuts {
  $shortcutNames = @()
  if ($manifest.shortcutNames) { $shortcutNames += @($manifest.shortcutNames) }
  if ($appName) { $shortcutNames += "$appName.lnk" }
  $shortcutNames = $shortcutNames | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique

  $locations = @(
    [Environment]::GetFolderPath("Desktop"),
    [Environment]::GetFolderPath("CommonDesktopDirectory"),
    (Join-Path ([Environment]::GetFolderPath("Programs")) $startMenuFolder),
    (Join-Path ([Environment]::GetFolderPath("CommonPrograms")) $startMenuFolder)
  ) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }

  foreach ($location in $locations) {
    foreach ($shortcut in $shortcutNames) {
      Remove-AtlasFile (Join-Path $location $shortcut)
    }
    Remove-AtlasFile (Join-Path $location "Uninstall $appName.lnk")
  }
}

function Remove-AtlasStartupEntries {
  $runKeys = @(
    "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"
  )
  $names = @()
  if ($manifest.startupEntryNames) { $names += @($manifest.startupEntryNames) }
  if ($appName) { $names += $appName }
  if ($exeName) { $names += [System.IO.Path]::GetFileNameWithoutExtension($exeName) }
  $names = $names | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique

  foreach ($key in $runKeys) {
    if (-not (Test-Path $key)) { continue }
    foreach ($name in $names) {
      Remove-ItemProperty -Path $key -Name $name -ErrorAction SilentlyContinue
    }
  }

  $startupFolder = [Environment]::GetFolderPath("Startup")
  foreach ($name in $names) {
    Remove-AtlasFile (Join-Path $startupFolder "$name.lnk")
  }
}

function Remove-AtlasTasks {
  if (-not $manifest.scheduledTasks) { return }
  foreach ($taskName in @($manifest.scheduledTasks)) {
    if ([string]::IsNullOrWhiteSpace($taskName)) { continue }
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
  }
}

function Remove-AtlasSettings {
  if (-not $manifest.dataDirectories) { return }
  foreach ($path in @($manifest.dataDirectories)) {
    Remove-AtlasDirectory ([string]$path)
  }
}

function Start-DeferredFolderDelete {
  param([string]$Folder)
  $folderPath = (Resolve-Path -LiteralPath $Folder).Path
  $cmd = "/c timeout /t 2 /nobreak >nul & rmdir /s /q `"$folderPath`""
  Start-Process -FilePath "cmd.exe" -ArgumentList $cmd -WindowStyle Hidden | Out-Null
}

Write-Host ""
Write-Host "ATLAS Uninstaller" -ForegroundColor Cyan
Write-Host "App:  $appName"
Write-Host "Mode: $Mode"
Write-Host ""

if (-not $Quiet) {
  Write-Host "AppOnly        = remove shortcuts, startup entries, and app folder"
  Write-Host "AppAndSettings = AppOnly + local settings/cache/logs"
  Write-Host "Everything     = AppAndSettings + app-managed data listed by the app"
  Write-Host ""
  if ($manifest.backupWarning) {
    Write-Host ([string]$manifest.backupWarning) -ForegroundColor Yellow
    Write-Host ""
  }
}

if (-not (Confirm-Atlas "Continue uninstalling $appName?")) {
  Write-Host "Uninstall cancelled."
  exit 0
}

Stop-AtlasProcesses
Remove-AtlasShortcuts
Remove-AtlasStartupEntries
Remove-AtlasTasks

if ($Mode -in @("AppAndSettings", "Everything")) {
  Remove-AtlasSettings
}

if ($Mode -eq "Everything" -and $manifest.everythingDirectories) {
  if (Confirm-Atlas "Remove app-managed data for $appName?") {
    foreach ($path in @($manifest.everythingDirectories)) {
      Remove-AtlasDirectory ([string]$path)
    }
  }
}

if ($Mode -eq "AppOnly" -or $Mode -eq "AppAndSettings" -or $Mode -eq "Everything") {
  if (Confirm-Atlas "Remove this app folder after the uninstaller closes?") {
    Start-DeferredFolderDelete -Folder $scriptDir
  }
}

Write-Host ""
Write-Host "$appName uninstall completed." -ForegroundColor Green
Write-Host "Backup files or user-selected destination folders are not removed unless they were explicitly listed and confirmed."
if (-not $Quiet) { pause }
