# ============================================================================
# Plugin Installer for Windows (PowerShell)
# ============================================================================

$ErrorActionPreference = "Stop"

# Plugin identity
$PLUGIN_NAME = "NextATC"
$PLUGIN_FOLDER = "$PLUGIN_NAME"

# Source directory = plugin subfolder next to this script
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
$SRC = Join-Path $SCRIPT_DIR $PLUGIN_FOLDER

# Files to preserve (user data)
$PRESERVE = @("settings.ini", "voices.ini", "FlightPlan.txt", "Settings.txt", "Voices.txt")

# Colors
function WriteW($t) { Write-Host $t -NoNewline }
function WriteP($t) { Write-Host $t -ForegroundColor Magenta -NoNewline }
function WriteY($t) { Write-Host $t -ForegroundColor DarkYellow -NoNewline }
function WriteR($t) { Write-Host $t -ForegroundColor Red -NoNewline }
function NL { Write-Host "" }

function Is-XPlane($dir) {
    if (-not (Test-Path "$dir\Resources\plugins")) { return $false }
    $score = 0
    if (Test-Path "$dir\Aircraft") { $score++ }
    if (Test-Path "$dir\Airfoils") { $score++ }
    if (Test-Path "$dir\Global Scenery") { $score++ }
    return ($score -ge 2)
}

function Get-SteamLibraries {
    $libraries = @()
    # Try registry without elevation
    $steamPath = (Get-ItemProperty -Path "HKCU:\Software\Valve\Steam" -ErrorAction SilentlyContinue).SteamPath
    if (-not $steamPath) {
        $steamPath = (Get-ItemProperty -Path "HKLM:\Software\Valve\Steam" -ErrorAction SilentlyContinue).InstallPath
    }
    if ($steamPath) {
        $libraries += $steamPath
        $vdfPath = Join-Path $steamPath "steamapps\libraryfolders.vdf"
        if (Test-Path $vdfPath) {
            $content = Get-Content $vdfPath -Raw
            $matches = [regex]::Matches($content, '"path"\s+"([^"]+)"')
            foreach ($m in $matches) {
                $lib = $m.Groups[1].Value -replace '\\\\', '\'
                if ($libraries -notcontains $lib) { $libraries += $lib }
            }
        }
    }
    return $libraries
}

function Find-Conflicting($xpDir) {
    $dirs = @()
    Get-ChildItem -Path "$xpDir\Resources\plugins" -Directory -Filter "124th*" -ErrorAction SilentlyContinue | ForEach-Object {
        if ($dirs -notcontains $_.FullName) { $dirs += $_.FullName }
    }
    Get-ChildItem -Path "$xpDir\Resources\plugins" -Filter "124th*.xpl" -Recurse -Depth 3 -ErrorAction SilentlyContinue | ForEach-Object {
        $pluginRoot = $_.Directory.Parent.FullName
        if ((Split-Path $pluginRoot -Leaf) -eq $PLUGIN_FOLDER) { return }
        if ($dirs -notcontains $pluginRoot) { $dirs += $pluginRoot }
    }
    return $dirs
}

# Banner
Clear-Host
NL
WriteP "  ======================================================"; NL
WriteP "          $PLUGIN_NAME - Installer for Windows (2026)      "; NL
if (Test-Path "$SRC\Version.txt") {
    $ver = (Get-Content "$SRC\Version.txt" -ErrorAction SilentlyContinue).Trim()
    WriteW "          Version: $ver"; NL
}
WriteP "  ======================================================"; NL
NL

# Verify source
if (-not (Test-Path $SRC)) {
    WriteR "  Error: Plugin folder not found at: $SRC"; NL
    WriteW "  Make sure the $PLUGIN_FOLDER folder is next to this script."; NL
    NL
    Read-Host "  Press Enter to close"
    exit 1
}

$hasBin = (Test-Path "$SRC\win_x64\$PLUGIN_FOLDER.xpl") -or (Test-Path "$SRC\mac_x64\$PLUGIN_FOLDER.xpl") -or (Test-Path "$SRC\lin_x64\$PLUGIN_FOLDER.xpl")
if (-not $hasBin) {
    WriteR "  Error: No plugin binaries found in: $SRC"; NL
    Read-Host "  Press Enter to close"
    exit 1
}

# Find X-Plane
$installs = @()
$XP_NAMES = @("X-Plane 12","X-Plane12","XPlane 12","XPlane12","X-Plane 11","X-Plane11","XPlane 11","XPlane11")

while ($installs.Count -eq 0) {
    WriteW "  How would you like to find your X-Plane installation?"; NL
    NL
    WriteW "    [S] Quick search - recommended (Steam + common locations)"; NL
    WriteW "    [D] Deep search - full scan (slower but exhaustive)"; NL
    WriteW "    [M] Enter path manually"; NL
    WriteW "    [Q] Quit"; NL
    NL
    $choice = Read-Host "  Select [S/d/m/q]"
    if (-not $choice) { $choice = "S" }

    if ($choice -eq "Q" -or $choice -eq "q") { exit 0 }

    if ($choice -eq "M" -or $choice -eq "m") {
        $mp = Read-Host "  Enter X-Plane folder path"
        if (Is-XPlane $mp) { $installs += $mp }
        else { WriteR "  Not a valid X-Plane folder."; NL; NL }
    }
    elseif ($choice -eq "D" -or $choice -eq "d") {
        WriteY "  Deep search started (this may take 1-3 minutes)..."; NL
        $drives = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match '^[A-Z]:\\$' } | Select-Object -ExpandProperty Root
        foreach ($drive in $drives) {
            Get-ChildItem -Path $drive -Filter "Global Scenery" -Directory -Recurse -Depth 8 -ErrorAction SilentlyContinue | ForEach-Object {
                $parent = $_.Parent.FullName
                if ((Test-Path "$parent\X-Plane.exe") -and (Is-XPlane $parent) -and ($installs -notcontains $parent)) {
                    $installs += $parent
                }
            }
        }
        if ($installs.Count -eq 0) { WriteR "  X-Plane not found. Try manual path."; NL; NL }
    }
    else {
        # Quick Search
        WriteW "  Quick search in progress..."; NL

        # Steam libraries via registry
        $steamLibs = Get-SteamLibraries
        foreach ($lib in $steamLibs) {
            foreach ($name in $XP_NAMES) {
                $d = Join-Path $lib "steamapps\common\$name"
                if ((Test-Path $d) -and (Is-XPlane $d) -and ($installs -notcontains $d)) { $installs += $d }
            }
        }

        # Root of all drives
        $drives = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match '^[A-Z]:\\$' } | Select-Object -ExpandProperty Root
        foreach ($drive in $drives) {
            foreach ($name in $XP_NAMES) {
                $d = Join-Path $drive $name
                if ((Test-Path $d) -and (Is-XPlane $d) -and ($installs -notcontains $d)) { $installs += $d }
            }
        }

        # Extra common paths
        $extraPaths = @(
            "$env:ProgramFiles\Steam\steamapps\common",
            "${env:ProgramFiles(x86)}\Steam\steamapps\common",
            "$env:USERPROFILE\Desktop"
        )
        foreach ($base in $extraPaths) {
            foreach ($name in $XP_NAMES) {
                $d = Join-Path $base $name
                if ((Test-Path $d) -and (Is-XPlane $d) -and ($installs -notcontains $d)) { $installs += $d }
            }
        }

        if ($installs.Count -eq 0) { 
            WriteY "  Not found in quick search. Try Deep search or manual path."; NL; NL 
        }
    }
}

# Select installation
NL
if ($installs.Count -eq 1) {
    WriteW "  Found: "; Write-Host $installs[0]
} elseif ($installs.Count -gt 1) {
    WriteW "  Found $($installs.Count) installations:"; NL; NL
    for ($i = 0; $i -lt $installs.Count; $i++) {
        WriteW "    [$($i+1)] $($installs[$i])"; NL
    }
    WriteW "    [A] Install to ALL"; NL
    WriteW "    [Q] Quit"; NL; NL
    $sel = Read-Host "  Select"
    if ($sel -eq "Q" -or $sel -eq "q") { exit 0 }
    if ($sel -eq "A" -or $sel -eq "a") {
        # keep all
    } elseif ($sel -match '^\d+$' -and [int]$sel -ge 1 -and [int]$sel -le $installs.Count) {
        $installs = @($installs[[int]$sel - 1])
    } else {
        WriteR "  Invalid selection."; NL; exit 1
    }
}

# Process each installation
foreach ($xp in $installs) {
    NL
    WriteP "  --- Processing: "; WriteW "$xp"; WriteP " ---"; NL

    $conflictingDirs = @(Find-Conflicting $xp)
    foreach ($d in $conflictingDirs) {
        WriteY "  Conflicting plugin found - will be backed up: $d"; NL
    }

    $dest = "$xp\Resources\plugins\$PLUGIN_FOLDER"
    $mode = "fresh"

    if (Test-Path $dest) {
        $mode = "update"
        NL; WriteY "  Existing installation: "; Write-Host $dest
        $installedVer = ""
        $newVer = ""
        if (Test-Path "$dest\Version.txt") {
            $installedVer = (Get-Content "$dest\Version.txt" -ErrorAction SilentlyContinue).Trim()
            WriteW "  Installed: $installedVer"; NL
        }
        if (Test-Path "$SRC\Version.txt") {
            $newVer = (Get-Content "$SRC\Version.txt" -ErrorAction SilentlyContinue).Trim()
            WriteW "  New:       $newVer"; NL
        }
        if ($installedVer -and $newVer -and ($installedVer -eq $newVer)) {
            $missing = @()
            Get-ChildItem -Path $SRC -File -Recurse | ForEach-Object {
                $rel = $_.FullName.Substring($SRC.Length + 1)
                if ($rel -match '(^CHANGELOG|\.DS_Store)') { return }
                if (-not (Test-Path "$dest\$rel")) { $missing += $rel }
            }
            if ($missing.Count -gt 0) {
                WriteY "  Incomplete installation detected - missing files:"; NL
                foreach ($mf in $missing) { WriteR "    $mf"; NL }
                WriteW "  Repairing..."; NL
                $mode = "repair"
            } else {
                WriteW "  Already up to date - skipping."; NL
                continue
            }
        }
    }

    NL
    WriteW "  Destination: "; Write-Host $dest
    if ($mode -eq "repair") {
        WriteW "  Action: "; WriteY "Repair in place"; NL
        WriteW "  Your settings and navdata will be preserved."; NL
    } elseif ($mode -eq "update") {
        WriteW "  Action: "; WriteY "Update in place"; NL
        WriteW "  Your settings and navdata will be preserved."; NL
    } else {
        WriteW "  Action: New installation"; NL
    }
    NL

    $go = Read-Host "  Proceed? [Y/n]"
    if ($go -ne "" -and $go -ne "Y" -and $go -ne "y") { Write-Host "  Skipped."; continue }

    NL
    if ($mode -eq "repair") { WriteW "  Repairing..."; NL } 
    elseif ($mode -eq "update") { WriteW "  Updating..."; NL } 
    else { WriteW "  Installing..."; NL }

    if (-not (Test-Path $dest)) {
        try { New-Item -Path $dest -ItemType Directory -Force | Out-Null }
        catch {
            WriteR "  Error: could not create plugin folder: $dest"; NL
            continue
        }
    }

    # Migrate navdata from old plugin
    if ($conflictingDirs.Count -gt 0 -and -not (Test-Path "$dest\navdata")) {
        foreach ($cdir in $conflictingDirs) {
            if (Test-Path "$cdir\navdata") {
                $navFiles = Get-ChildItem "$cdir\navdata" -File -Recurse -ErrorAction SilentlyContinue
                if ($navFiles.Count -gt 0) {
                    NL
                    $cdirName = Split-Path $cdir -Leaf
                    WriteW "  Navdata found in `"$cdirName`" ($($navFiles.Count) files)."; NL
                    $migNav = Read-Host "  Migrate navdata to $PLUGIN_NAME? [Y/n]"
                    if ($migNav -eq "" -or $migNav -eq "Y" -or $migNav -eq "y") {
                        try {
                            Move-Item "$cdir\navdata" "$dest\navdata" -Force
                            WriteW "  Navdata migrated."; NL
                        } catch { WriteR "  Error: could not migrate navdata."; NL }
                    }
                    break
                }
            }
        }
    }

    # Clean old binaries
    if ($mode -eq "update" -or $mode -eq "repair") {
        foreach ($pd in @("mac_x64","win_x64","lin_x64","64")) {
            Remove-Item "$dest\$pd\*.xpl" -Force -ErrorAction SilentlyContinue
            Remove-Item "$dest\$pd\*.dll" -Force -ErrorAction SilentlyContinue
        }
    }

    # Copy files
    $copyErrors = 0
    Get-ChildItem -Path $SRC -File -Recurse | ForEach-Object {
        $rel = $_.FullName.Substring($SRC.Length + 1)
        if ($rel -match '\.DS_Store') { return }
        $destFile = Join-Path $dest $rel
        $destDir = Split-Path $destFile -Parent
        if ($PRESERVE -contains $rel -and (Test-Path $destFile)) { return }
        if ($rel -match '^navdata\\' -and (Test-Path "$dest\navdata")) { return }
        if (-not (Test-Path $destDir)) {
            try { New-Item $destDir -ItemType Directory -Force | Out-Null }
            catch { $script:copyErrors++; return }
        }
        try { Copy-Item $_.FullName $destFile -Force }
        catch { $script:copyErrors++ }
    }
    if ($copyErrors -gt 0) {
        WriteR "  Warning: $copyErrors file(s) failed to copy."; NL
    }

    # Archive conflicting plugins
    if ($conflictingDirs.Count -gt 0) {
        $backupDir = "$dest\backup"
        if (-not (Test-Path $backupDir)) { New-Item -Path $backupDir -ItemType Directory -Force | Out-Null }
        $archive = "$backupDir\legacy.zip"
        try {
            Compress-Archive -Path $conflictingDirs -DestinationPath $archive -Force
            WriteW "  Conflicting plugins archived -> $PLUGIN_NAME\backup\legacy.zip"; NL
            foreach ($cdir in $conflictingDirs) {
                Remove-Item $cdir -Recurse -Force -ErrorAction SilentlyContinue
            }
        } catch {
            WriteR "  Could not archive conflicting plugins."; NL
        }
    }

    NL
    WriteP "  ======================================================"; NL
    if ($mode -eq "repair") {
        WriteW "  Repair complete!"; NL
    } elseif ($mode -eq "update" -and $installedVer) {
        $finalVer = (Get-Content "$dest\Version.txt" -ErrorAction SilentlyContinue).Trim()
        WriteW "  Update complete!  $installedVer -> $finalVer"; NL
    } else {
        WriteW "  Installation complete!"; NL
    }
    WriteW "  Location: $dest"; NL
    WriteP "  ======================================================"; NL
    NL
}

WriteP "  Enjoy $PLUGIN_NAME!"; NL
NL

# Show changelog if available
$clPath = "$SRC\CHANGELOG.md"
if (Test-Path $clPath) {
    Read-Host "  Press Enter to view changelog"
    NL
    WriteP "  === Changelog ==="; NL
    NL
    Get-Content $clPath -TotalCount 60 | ForEach-Object { Write-Host "  $_" }
    NL
}

Read-Host "  Press Enter to close"