#Requires -RunAsAdministrator
<#
.SYNOPSIS
    DeployPro Windows Installer
.DESCRIPTION
    Automatically installs prerequisites (Node.js LTS, IIS), copies files,
    runs npm install, installs the Windows service, and opens the browser.
.NOTES
    Must be run as Administrator.
#>

$ErrorActionPreference = "Stop"
$ProgressPreference    = "SilentlyContinue"  # Faster downloads

# ─── Configuration ────────────────────────────────────────────────────────────
$AppName     = "DeployPro"
$ServiceName = "deploypro.exe"
$DefaultPort = 7070
$NodeMinVer  = 18
$NodeLtsUrl  = "https://nodejs.org/dist/v20.11.1/node-v20.11.1-x64.msi"

# Installation directory (default: C:\DeployPro, or provided via arg)
$InstallDir  = if ($args[0]) { $args[0] } else { "C:\DeployPro" }

# ─── Helpers ──────────────────────────────────────────────────────────────────
function Write-Step($n, $msg) {
    Write-Host ""
    Write-Host "  [$n] $msg" -ForegroundColor Cyan
}

function Write-OK($msg)   { Write-Host "      OK: $msg" -ForegroundColor Green }
function Write-Info($msg) { Write-Host "      >>  $msg" -ForegroundColor Gray }
function Write-Warn($msg) { Write-Host "      !!  $msg" -ForegroundColor Yellow }
function Write-Fail($msg) { Write-Host "      ERR: $msg" -ForegroundColor Red ; exit 1 }

# ─── Banner ───────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "  ╔══════════════════════════════════════════════╗" -ForegroundColor DarkCyan
Write-Host "  ║   DeployPro Installer  —  Enterprise IIS     ║" -ForegroundColor DarkCyan
Write-Host "  ╚══════════════════════════════════════════════╝" -ForegroundColor DarkCyan
Write-Host ""
Write-Host "  Install directory : $InstallDir"
Write-Host "  Service port      : $DefaultPort"
Write-Host ""

# ─── Step 1: Check / Install Node.js ─────────────────────────────────────────
Write-Step 1 "Checking Node.js..."

$nodeOk = $false
try {
    $nodeVer = & node --version 2>$null
    if ($nodeVer -match "v(\d+)") {
        $major = [int]$Matches[1]
        if ($major -ge $NodeMinVer) {
            Write-OK "Node.js $nodeVer already installed"
            $nodeOk = $true
        } else {
            Write-Warn "Node.js $nodeVer is too old (need v$NodeMinVer+). Will upgrade."
        }
    }
} catch { $nodeVer = $null }

if (-not $nodeOk) {
    Write-Info "Downloading Node.js LTS from nodejs.org..."
    $msiPath = "$env:TEMP\nodejs-lts.msi"
    Invoke-WebRequest -Uri $NodeLtsUrl -OutFile $msiPath -UseBasicParsing
    Write-Info "Installing Node.js (silent)..."
    Start-Process msiexec.exe -ArgumentList "/i `"$msiPath`" /qn /norestart ADDLOCAL=ALL" -Wait -NoNewWindow
    Remove-Item $msiPath -Force -ErrorAction SilentlyContinue
    # Refresh PATH
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
                [System.Environment]::GetEnvironmentVariable("Path", "User")
    Write-OK "Node.js installed successfully"
}

# ─── Step 2: Check / Enable IIS ──────────────────────────────────────────────
Write-Step 2 "Checking IIS..."

$iisFeature = Get-WindowsOptionalFeature -Online -FeatureName "IIS-WebServer" -ErrorAction SilentlyContinue
if ($iisFeature -and $iisFeature.State -eq "Enabled") {
    Write-OK "IIS is already enabled"
} else {
    Write-Info "Enabling IIS (this may take a few minutes)..."
    $features = @(
        "IIS-WebServer",
        "IIS-WebServerManagementTools",
        "IIS-ManagementConsole",
        "IIS-DefaultDocument",
        "IIS-StaticContent",
        "IIS-ASPNET45",
        "IIS-NetFxExtensibility45",
        "IIS-ISAPIExtensions",
        "IIS-ISAPIFilter",
        "IIS-HttpCompressionStatic",
        "IIS-HttpLogging",
        "IIS-RequestFiltering",
        "Web-Asp-Net45",
        "Web-Net-Ext45"
    )
    foreach ($f in $features) {
        Enable-WindowsOptionalFeature -Online -FeatureName $f -NoRestart -ErrorAction SilentlyContinue | Out-Null
    }
    Write-OK "IIS enabled"
}

# ─── Step 3: Copy application files ──────────────────────────────────────────
Write-Step 3 "Installing DeployPro to $InstallDir..."

# Determine source directory (same folder as this script)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path

# Create destination
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null

# Copy all app files (exclude installer subfolder, node_modules, data, uploads, backups, logs)
$excludeDirs = @("installer", "node_modules", "data", "uploads", "backups", "logs", "dist")
Get-ChildItem -Path $ScriptDir -Recurse | Where-Object {
    $rel = $_.FullName.Substring($ScriptDir.Length + 1)
    $topLevel = $rel.Split([IO.Path]::DirectorySeparatorChar)[0]
    $topLevel -notin $excludeDirs
} | ForEach-Object {
    $dest = Join-Path $InstallDir $_.FullName.Substring($ScriptDir.Length + 1)
    if ($_.PSIsContainer) {
        New-Item -ItemType Directory -Path $dest -Force | Out-Null
    } else {
        $destDir = Split-Path $dest -Parent
        New-Item -ItemType Directory -Path $destDir -Force | Out-Null
        Copy-Item $_.FullName -Destination $dest -Force
    }
}

# Create data directories
@("data","uploads","backups","logs","dist") | ForEach-Object {
    New-Item -ItemType Directory -Path (Join-Path $InstallDir $_) -Force | Out-Null
}

Write-OK "Files copied to $InstallDir"

# ─── Step 4: npm install ─────────────────────────────────────────────────────
Write-Step 4 "Installing npm dependencies..."

Push-Location $InstallDir
npm install --production --no-audit --no-fund 2>&1 | Write-Host
Pop-Location
Write-OK "npm install complete"

# ─── Step 5: Configure JWT secret ────────────────────────────────────────────
Write-Step 5 "Generating JWT secret..."

# Generate a random 64-char secret and persist it via environment variable
$secret = -join (1..64 | ForEach-Object { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[[int](Get-Random -Max 62)] })
[System.Environment]::SetEnvironmentVariable("JWT_SECRET", $secret, "Machine")
Write-OK "JWT_SECRET set in system environment"

# ─── Step 6: Install Windows Service ─────────────────────────────────────────
Write-Step 6 "Installing Windows service..."

# Stop + remove existing service if present
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($svc) {
    if ($svc.Status -eq "Running") {
        Write-Info "Stopping existing service..."
        Stop-Service -Name $ServiceName -Force
        Start-Sleep 2
    }
    # Use node-windows uninstall script if present
    $uninstall = Join-Path $InstallDir "uninstall-service.bat"
    if (Test-Path $uninstall) {
        Start-Process cmd.exe -ArgumentList "/c `"$uninstall`"" -Wait -NoNewWindow -WorkingDirectory $InstallDir
    }
    Start-Sleep 2
}

# Run install-service.bat (which uses node-windows)
$install = Join-Path $InstallDir "install-service.bat"
if (Test-Path $install) {
    Start-Process cmd.exe -ArgumentList "/c `"$install`"" -Wait -NoNewWindow -WorkingDirectory $InstallDir
    Start-Sleep 3
    Write-OK "Windows service installed"
} else {
    Write-Warn "install-service.bat not found — service not registered. Run it manually."
}

# ─── Step 7: Firewall rule ────────────────────────────────────────────────────
Write-Step 7 "Configuring firewall..."

$fwRule = Get-NetFirewallRule -DisplayName "DeployPro" -ErrorAction SilentlyContinue
if ($fwRule) {
    Write-OK "Firewall rule already exists"
} else {
    New-NetFirewallRule `
        -DisplayName "DeployPro" `
        -Description "Allow DeployPro web app on port $DefaultPort" `
        -Direction Inbound `
        -Protocol TCP `
        -LocalPort $DefaultPort `
        -Action Allow | Out-Null
    Write-OK "Firewall rule created for port $DefaultPort"
}

# ─── Step 8: Start service ────────────────────────────────────────────────────
Write-Step 8 "Starting the service..."

$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($svc) {
    Start-Service -Name $ServiceName -ErrorAction SilentlyContinue
    Start-Sleep 3
    $svc.Refresh()
    if ($svc.Status -eq "Running") {
        Write-OK "Service is running"
    } else {
        Write-Warn "Service may not have started. Check Event Viewer."
    }
} else {
    Write-Warn "Service not found — you may need to run install-service.bat manually"
}

# ─── Done ──────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "  ╔══════════════════════════════════════════════╗" -ForegroundColor Green
Write-Host "  ║   Installation Complete!                     ║" -ForegroundColor Green
Write-Host "  ╚══════════════════════════════════════════════╝" -ForegroundColor Green
Write-Host ""
Write-Host "  URL            : http://localhost:$DefaultPort" -ForegroundColor White
Write-Host "  Default login  : admin / Admin@123" -ForegroundColor Yellow
Write-Host "  Install path   : $InstallDir" -ForegroundColor White
Write-Host ""
Write-Host "  IMPORTANT: Change the default admin password immediately!" -ForegroundColor Red
Write-Host ""

# Open browser
Start-Process "http://localhost:$DefaultPort"
