payload/uninstall.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    furnizsh — uninstaller for Windows / PowerShell.
 
.DESCRIPTION
    Removes the furnizsh PowerShell profile and optionally restores whatever
    was there before, unsets the git-delta config, and can strip the colour
    schemes from Windows Terminal.
 
    It does NOT uninstall the tools (starship, eza, bat, ...) or the PowerShell
    modules unless you pass -Tools — they're useful on their own and you
    probably want to keep them.
 
.PARAMETER DryRun
    Print every action without changing anything.
 
.PARAMETER Yes
    Don't prompt for confirmation.
 
.PARAMETER Restore
    Restore the profile and configs from the most recent backup.
 
.PARAMETER Tools
    Also uninstall the CLI tools and PowerShell modules (asks first).
 
.PARAMETER Schemes
    Also remove the furnizsh colour schemes from Windows Terminal.
 
.EXAMPLE
    .\uninstall.ps1 -DryRun
 
.EXAMPLE
    .\uninstall.ps1 -Restore
#>


[CmdletBinding()]
param(
    [switch]$DryRun,
    [switch]$Yes,
    [switch]$Restore,
    [switch]$Tools,
    [switch]$Schemes
)

$ErrorActionPreference = 'Stop'

$BackupRoot = Join-Path $HOME '.furnizsh-backup'

$C = @{
    Orange = "`e[38;2;250;179;135m"
    Green  = "`e[38;2;166;227;161m"
    Blue   = "`e[38;2;137;180;250m"
    Gray   = "`e[38;2;108;112;134m"
    Bold   = "`e[1m"
    Reset  = "`e[0m"
}

function Write-Step { param([string]$m) Write-Host "`n$($C.Bold)$($C.Blue)==>$($C.Reset) $m" }
function Write-Info { param([string]$m) Write-Host " $m" }
function Write-Ok   { param([string]$m) Write-Host " $($C.Green)OK$($C.Reset) $m" }
function Write-Skip { param([string]$m) Write-Host " $($C.Gray)- $m$($C.Reset)" }
function Write-Warn { param([string]$m) Write-Host " $($C.Orange)! $m$($C.Reset)" }

function Invoke-Step {
    param([string]$Description, [scriptblock]$Action)
    if ($DryRun) { Write-Host " $($C.Gray)[dry-run]$($C.Reset) $Description" }
    else { & $Action }
}

function Confirm-Action {
    param([string]$Message)
    if ($Yes -or $DryRun) { return $true }
    return (Read-Host " $Message [y/N]") -match '^[yY]'
}

function Get-NewestBackup {
    if (-not (Test-Path $BackupRoot)) { return $null }
    Get-ChildItem $BackupRoot -Directory -ErrorAction SilentlyContinue |
        Sort-Object Name -Descending | Select-Object -First 1
}

# ------------------------------------------------------------
function Remove-FurnizshProfile {
    Write-Step "Removing the PowerShell profile"

    if (-not (Test-Path $PROFILE)) { Write-Skip "no profile at $PROFILE"; return }

    $content = Get-Content $PROFILE -Raw -ErrorAction SilentlyContinue
    if ($content -notmatch 'furnizsh') {
        Write-Warn "the profile at $PROFILE isn't furnizsh's — leaving it alone"
        return
    }

    # Keep a safety copy regardless of what else happens.
    Invoke-Step "back up and remove $PROFILE" {
        Copy-Item $PROFILE "$PROFILE.furnizsh-uninstall.bak" -Force
        Remove-Item $PROFILE -Force
    }
    Write-Ok "removed (pre-uninstall copy at $(Split-Path $PROFILE -Leaf).furnizsh-uninstall.bak)"
}

function Restore-Backup {
    if (-not $Restore) { return }

    Write-Step "Restoring from backup"

    $newest = Get-NewestBackup
    if (-not $newest) { Write-Warn "no backups found under $BackupRoot"; return }

    Write-Info "Newest backup: $($newest.FullName)"
    Get-ChildItem $newest.FullName | ForEach-Object { Write-Info " $($_.Name)" }

    Write-Warn "Restoring copies files back over your current config."
    if (-not (Confirm-Action "Restore them?")) { Write-Skip "left as-is"; return }

    # install.ps1 only ever backs up this fixed set, so an explicit table is
    # safer than trying to infer where each file came from.
    $map = @{
        'Microsoft.PowerShell_profile.ps1' = $PROFILE
        'starship.toml'                    = "$HOME\.config\starship.toml"
        'config.yml'                       = "$env:APPDATA\lazygit\config.yml"
        'settings.json'                    = "$env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
    }

    foreach ($file in Get-ChildItem $newest.FullName -File) {
        $dest = $map[$file.Name]
        if (-not $dest) { Write-Warn "don't know where $($file.Name) came from - skipping"; continue }

        Invoke-Step "restore $($file.Name) -> $dest" {
            New-Item -ItemType Directory -Force -Path (Split-Path $dest -Parent) | Out-Null
            Copy-Item $file.FullName -Destination $dest -Force
        }
        Write-Ok "restored $dest"
    }
}

function Reset-GitDelta {
    Write-Step "git-delta"

    # Assigned first rather than inlined: `2>$null` inside an if condition
    # trips PSScriptAnalyzer's redirection-operator check, and this reads
    # better anyway.
    $currentPager = git config --global core.pager 2>$null
    if ($currentPager -ne 'delta') {
        Write-Skip "delta isn't the configured pager"
        return
    }
    if (-not (Confirm-Action "Unset delta as your git pager?")) { Write-Skip "left as-is"; return }

    Invoke-Step "git config --global --unset core.pager (and friends)" {
        git config --global --unset core.pager 2>$null
        git config --global --unset interactive.diffFilter 2>$null
        git config --global --unset delta.navigate 2>$null
    }
    Write-Ok "unset"
}

function Remove-TerminalScheme {
    if (-not $Schemes) { return }

    Write-Step "Windows Terminal colour schemes"

    $settingsPath = "$env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
    if (-not (Test-Path $settingsPath)) { Write-Skip "Windows Terminal settings not found"; return }

    if (-not (Confirm-Action "Remove the 'Catppuccin Mocha' and 'Furnizsh Neon' schemes?")) {
        Write-Skip "kept"; return
    }

    Invoke-Step "strip furnizsh schemes from settings.json" {
        Copy-Item $settingsPath "$settingsPath.furnizsh-uninstall.bak" -Force
        $settings = Get-Content $settingsPath -Raw | ConvertFrom-Json
        $ours = @('Catppuccin Mocha', 'Furnizsh Neon')
        $settings.schemes = @($settings.schemes | Where-Object { $ours -notcontains $_.name })
        $settings | ConvertTo-Json -Depth 32 | Set-Content $settingsPath -Encoding UTF8
    }
    Write-Ok "removed"
    Write-Warn "any profile still set to one of those schemes will fall back to its default"
}

function Remove-ToolSet {
    if (-not $Tools) { return }

    Write-Step "Uninstalling tools"
    Write-Warn "This removes starship, zoxide, eza, bat, fd, delta, lazygit and fzf."
    Write-Warn "They're useful outside furnizsh — you probably want to keep them."
    if (-not (Confirm-Action "Uninstall them anyway?")) { Write-Skip "kept"; return }

    $ids = @(
        @{ winget = 'Starship.Starship';      scoop = 'starship' },
        @{ winget = 'ajeetdsouza.zoxide';     scoop = 'zoxide'   },
        @{ winget = 'junegunn.fzf';           scoop = 'fzf'      },
        @{ winget = 'eza-community.eza';      scoop = 'eza'      },
        @{ winget = 'sharkdp.bat';            scoop = 'bat'      },
        @{ winget = 'sharkdp.fd';             scoop = 'fd'       },
        @{ winget = 'dandavison.delta';       scoop = 'delta'    },
        @{ winget = 'JesseDuffield.lazygit';  scoop = 'lazygit'  }
    )

    $pkg = if (Get-Command winget -ErrorAction SilentlyContinue) { 'winget' }
           elseif (Get-Command scoop -ErrorAction SilentlyContinue) { 'scoop' }
           else { $null }

    if (-not $pkg) { Write-Warn "no winget or scoop found — remove them by hand"; return }

    foreach ($id in $ids) {
        Invoke-Step "$pkg uninstall $($id[$pkg])" {
            if ($pkg -eq 'winget') { winget uninstall --id $id['winget'] --silent 2>$null | Out-Null }
            else { scoop uninstall $id['scoop'] 2>$null | Out-Null }
        }
    }
    Write-Ok "tools removed"

    if (Confirm-Action "Also remove the Terminal-Icons and PSFzf modules?") {
        foreach ($m in @('Terminal-Icons', 'PSFzf')) {
            Invoke-Step "Uninstall-Module $m" { Uninstall-Module $m -AllVersions -Force -ErrorAction SilentlyContinue }
        }
        Write-Ok "modules removed"
        Write-Info "PSReadLine is left alone — Windows ships and depends on it."
    }
}

# ------------------------------------------------------------
Write-Host "`n$($C.Bold)$($C.Blue) furnizsh uninstall$($C.Reset) $($C.Gray)(PowerShell)$($C.Reset)"
if ($DryRun) { Write-Host "`n $($C.Bold)$($C.Orange)DRY RUN - nothing will be changed.$($C.Reset)" }

try {
    Remove-FurnizshProfile
    Restore-Backup
    Reset-GitDelta
    Remove-TerminalScheme
    Remove-ToolSet

    Write-Step "Done"
    if ($DryRun) {
        Write-Info "That was a dry run. Rerun without -DryRun to apply."
    } else {
        Write-Info "Open a new PowerShell window for the change to take effect."
        if (Test-Path $BackupRoot) {
            Write-Info "Your backups are still at $BackupRoot - delete them when you're happy."
        }
    }
    Write-Host ""
}
catch {
    Write-Host "`n$($C.Bold)$($C.Orange)error:$($C.Reset) $($_.Exception.Message)`n"
    exit 1
}