param(
    [bool]$RequireConfirmation = $true
)

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

function Write-Step {
    param([string]$Message)

    Write-Host ""
    Write-Host "==> $Message" -ForegroundColor Cyan
}

function Write-Info {
    param([string]$Message)

    Write-Host "    $Message" -ForegroundColor DarkGray
}

function Test-CommandExists {
    param([string]$Name)

    return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
}

function Test-NodeVersionSupported {
    if (-not (Test-CommandExists -Name "node")) {
        return $false
    }

    try {
        $versionText = (& node --version).Trim().TrimStart("v")
        $version = [Version]$versionText
        return $version -ge ([Version]"22.16.0")
    } catch {
        return $false
    }
}

function Add-PathIfMissing {
    param([string]$PathToAdd)

    if ([string]::IsNullOrWhiteSpace($PathToAdd)) {
        return
    }

    $expanded = [Environment]::ExpandEnvironmentVariables($PathToAdd).TrimEnd("\")
    if (-not (Test-Path $expanded)) {
        return
    }

    $currentParts = @($env:PATH -split ";" | Where-Object { $_ -and $_.Trim() -ne "" })
    $normalized = $currentParts | ForEach-Object { $_.TrimEnd("\") }

    if ($normalized -contains $expanded) {
        return
    }

    $env:PATH = ($currentParts + $expanded) -join ";"
}

function Refresh-SessionPath {
    $machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
    $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
    $combined = @($machinePath, $userPath, $env:PATH) | Where-Object { $_ -and $_.Trim() -ne "" }
    $env:PATH = ($combined -join ";")

    try {
        $npmPrefix = & npm config get prefix 2>$null
        if ($LASTEXITCODE -eq 0 -and $npmPrefix) {
            Add-PathIfMissing -PathToAdd $npmPrefix.Trim()
            Add-PathIfMissing -PathToAdd (Join-Path $npmPrefix.Trim() "bin")
        }
    } catch {
        Write-Info "npm is not available yet; PATH will be refreshed after install."
    }
}

function Ensure-N8nOnPath {
    Refresh-SessionPath

    $command = Get-Command n8n -ErrorAction SilentlyContinue
    if ($command) {
        return $command.Source
    }

    $fallbacks = @(
        (Join-Path $HOME "AppData\Roaming\npm\n8n.cmd"),
        (Join-Path $HOME "AppData\Local\npm\n8n.cmd")
    )

    foreach ($candidate in $fallbacks) {
        if (Test-Path $candidate) {
            Add-PathIfMissing -PathToAdd (Split-Path $candidate -Parent)
            return $candidate
        }
    }

    throw "n8n was installed, but the command is still not available in PATH."
}

function Install-NodeFromLocalMsi {
    param(
        [Parameter(Mandatory = $true)][string]$MsiPath
    )

    if (-not (Test-Path $MsiPath)) {
        throw "Node.js installer not found: $MsiPath"
    }

    Write-Step "Installing Node.js from local MSI"
    Write-Info $MsiPath
    & msiexec.exe /i $MsiPath /qn /norestart
    if ($LASTEXITCODE -ne 0) {
        throw "Node.js MSI install failed with exit code $LASTEXITCODE."
    }

    Refresh-SessionPath
    if (-not (Test-NodeVersionSupported)) {
        throw "Node.js installation completed, but node >= 22.16.0 is still not available in PATH."
    }
}

function Install-N8nFromLocalPackage {
    param(
        [Parameter(Mandatory = $true)][string]$PackagePath
    )

    if (-not (Test-Path $PackagePath)) {
        throw "n8n package not found: $PackagePath"
    }

    if (-not (Test-CommandExists -Name "npm")) {
        throw "npm is not available after Node.js installation."
    }

    Write-Step "Installing n8n from local package"
    Write-Info $PackagePath
    & npm install -g --no-fund --no-audit --loglevel=error $PackagePath
    if ($LASTEXITCODE -ne 0) {
        throw "Local n8n install failed with exit code $LASTEXITCODE."
    }
}

function Ensure-N8nUserDirectory {
    $userDir = Join-Path $HOME ".n8n"
    if (-not (Test-Path $userDir)) {
        New-Item -Path $userDir -ItemType Directory -Force | Out-Null
    }

    return $userDir
}

if ($RequireConfirmation) {
    Write-Step "Preparing local n8n installation"
    Write-Host "This will install Node.js if needed and then install n8n globally for the current Windows user." -ForegroundColor Yellow
    $confirmation = Read-Host "Continue? [Y/N]"
    if ($confirmation -notmatch "^(?i:y|yes)$") {
        throw "Installation cancelled by user."
    }
}

$packagesDir = Join-Path $PSScriptRoot "packages"
$nodeMsiPath = Join-Path $packagesDir "node-v22.22.2-x64.msi"
$n8nPackagePath = Join-Path $packagesDir "n8n-2.13.3.tgz"

if (Test-NodeVersionSupported) {
    Write-Step "Node.js already installed"
    Write-Info ((& node --version).Trim())
} else {
    Install-NodeFromLocalMsi -MsiPath $nodeMsiPath
}

Install-N8nFromLocalPackage -PackagePath $n8nPackagePath
$n8nPath = Ensure-N8nOnPath
$userDir = Ensure-N8nUserDirectory

Write-Step "n8n found"
Write-Info $n8nPath

Write-Step "n8n version"
Write-Info ((& n8n --version).Trim())

Write-Step "User data directory"
Write-Info $userDir

Write-Host ""
Write-Host "n8n installation is complete." -ForegroundColor Green
Write-Host "Run START_N8N.bat to launch the local interface." -ForegroundColor Green
Write-Host "Default URL: http://127.0.0.1:5678" -ForegroundColor Green
