#Requires -Version 5.1
<#
.SYNOPSIS
  CNPERP Local Server installer — PostgreSQL, Python deps, DB init, desktop shortcuts, cloud license link.

.DESCRIPTION
  Run from the CNPERP repository root (or pass -InstallPath).
  After install: use desktop shortcut "CNPERP Server" for LAN access,
  complete license + company setup at http://localhost:8010/setup

.PARAMETER InstallPath
  Folder containing app\main.py (defaults to repo root when run from deploy\local-server)

.PARAMETER CloudUrl
  CNP cloud hub URL for license validation (customer downloads license from your website)

.PARAMETER DbPassword
  Password for PostgreSQL user cnperp_user (generated if omitted)

.PARAMETER Port
  HTTP port for local ERP (default 8010)

.PARAMETER SkipPythonDeps
  Skip pip install (if already done)

.PARAMETER SkipDbBootstrap
  Skip schema/seed (if already initialized)
#>
param(
    [string]$InstallPath = "",
    [string]$CloudUrl = "https://erp.cnpsolutions.co.bw",
    [string]$DbPassword = "",
    [int]$Port = 8010,
    [switch]$SkipPythonDeps,
    [switch]$SkipDbBootstrap,
    [switch]$SkipFirewall,
    [switch]$NoDesktopShortcut,
    [switch]$LaunchSetup
)

$ErrorActionPreference = "Stop"

function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
function Write-Ok($msg)   { Write-Host "    [OK] $msg" -ForegroundColor Green }
function Write-Warn($msg) { Write-Host "    [!!] $msg" -ForegroundColor Yellow }
function Write-Fail($msg) { Write-Host "    [FAIL] $msg" -ForegroundColor Red }

function Resolve-InstallRoot {
    if ($InstallPath) {
        $p = Resolve-Path $InstallPath -ErrorAction Stop
        return $p.Path
    }
    $defaultZipPath = "C:\CNPERP"
    if (Test-Path (Join-Path $defaultZipPath "app\main.py")) {
        return $defaultZipPath
    }
    $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
    $root = (Resolve-Path (Join-Path $scriptDir "..\..")).Path
    if (-not (Test-Path (Join-Path $root "app\main.py"))) {
        throw @"
CNPERP folder not found. Extract the ZIP to C:\ so you have C:\CNPERP\app\main.py
Then run:  cd C:\CNPERP
           .\deploy\local-server\Install-CNPERP-Local.ps1
Or pass -InstallPath to your CNPERP folder.
"@
    }
    return $root
}

function Test-Command($name) {
    return $null -ne (Get-Command $name -ErrorAction SilentlyContinue)
}

function Find-PostgreSqlBin {
    $candidates = @(
        "C:\Program Files\PostgreSQL\16\bin",
        "C:\Program Files\PostgreSQL\15\bin",
        "C:\Program Files\PostgreSQL\14\bin"
    )
    foreach ($c in $candidates) {
        if (Test-Path (Join-Path $c "psql.exe")) { return $c }
    }
    if (Test-Command "psql") {
        return (Split-Path -Parent (Get-Command psql).Source)
    }
    return $null
}

function Test-PostgreSqlService {
    $svc = Get-Service -Name "postgresql*" -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Running' } | Select-Object -First 1
    return ($null -ne $svc)
}

function New-DesktopShortcut($name, $target, $arguments, $workingDir, $iconPath) {
    $desktop = [Environment]::GetFolderPath("Desktop")
    $lnk = Join-Path $desktop "$name.lnk"
    $wsh = New-Object -ComObject WScript.Shell
    $sc = $wsh.CreateShortcut($lnk)
    $sc.TargetPath = $target
    if ($arguments) { $sc.Arguments = $arguments }
    $sc.WorkingDirectory = $workingDir
    if ($iconPath -and (Test-Path $iconPath)) { $sc.IconLocation = "$iconPath,0" }
    $sc.Description = "CNPERP Local ERP"
    $sc.Save()
    return $lnk
}

function New-InternetShortcutUrl($name, $url, $iconPath) {
    $desktop = [Environment]::GetFolderPath("Desktop")
    $path = Join-Path $desktop "$name.url"
    $lines = @(
        "[InternetShortcut]",
        "URL=$url"
    )
    if ($iconPath -and (Test-Path $iconPath)) {
        $lines += "IconFile=$iconPath"
        $lines += "IconIndex=0"
    }
    Set-Content -Path $path -Value ($lines -join "`r`n") -Encoding ASCII
    return $path
}

# ── Start ────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "CNP Solutions — CNPERP Local Server Installer" -ForegroundColor White
Write-Host "=============================================" -ForegroundColor White

$Root = Resolve-InstallRoot
Set-Location $Root
Write-Ok "Install path: $Root"

# ── 1. Python ───────────────────────────────────────────────────────────────
Write-Step "Checking Python"
if (-not (Test-Command "python")) {
    Write-Fail "Python not found. Install Python 3.11+: winget install Python.Python.3.11"
    exit 1
}
$pyVer = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
if ([version]$pyVer -lt [version]"3.10") {
    Write-Fail "Python 3.10+ required (found $pyVer)"
    exit 1
}
Write-Ok "Python $pyVer"

# ── 2. PostgreSQL ───────────────────────────────────────────────────────────
Write-Step "Checking PostgreSQL"
$pgBin = Find-PostgreSqlBin
if (-not $pgBin) {
    Write-Fail "PostgreSQL not found. Install: winget install PostgreSQL.PostgreSQL.15"
    Write-Host "    Then re-run this installer." -ForegroundColor Gray
    exit 1
}
Write-Ok "PostgreSQL bin: $pgBin"

if (-not (Test-PostgreSqlService)) {
    Write-Warn "PostgreSQL service not running. Attempting to start..."
    Get-Service -Name "postgresql*" -ErrorAction SilentlyContinue | ForEach-Object {
        try { Start-Service $_.Name -ErrorAction SilentlyContinue } catch { }
    }
    Start-Sleep -Seconds 3
    if (-not (Test-PostgreSqlService)) {
        Write-Warn "Start PostgreSQL manually from Services (services.msc), then re-run installer."
    }
}

$psql = Join-Path $pgBin "psql.exe"
$DbName = "cnperp_local"
$DbUser = "cnperp_user"
if (-not $DbPassword) {
    $DbPassword = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 16 | ForEach-Object { [char]$_ })
    Write-Ok "Generated database password (saved in .env)"
}

Write-Step "Creating PostgreSQL database and user"
Write-Host "    You may be prompted for the PostgreSQL superuser (postgres) password." -ForegroundColor Gray
$sql = @"
SELECT 1 FROM pg_roles WHERE rolname='$DbUser';
"@
$roleExists = & $psql -U postgres -tAc $sql 2>$null
if ($LASTEXITCODE -ne 0) {
    Write-Warn "Could not connect as postgres. Create manually:"
    Write-Host "      CREATE DATABASE $DbName; CREATE USER $DbUser WITH PASSWORD '...'; GRANT ALL ON DATABASE $DbName TO $DbUser;" -ForegroundColor Gray
} else {
    if (-not ($roleExists -match "1")) {
        & $psql -U postgres -c "CREATE USER $DbUser WITH PASSWORD '$DbPassword';" 2>$null
    } else {
        & $psql -U postgres -c "ALTER USER $DbUser WITH PASSWORD '$DbPassword';" 2>$null
    }
    $dbExists = & $psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$DbName';" 2>$null
    if (-not ($dbExists -match "1")) {
        & $psql -U postgres -c "CREATE DATABASE $DbName OWNER $DbUser;" 2>$null
    }
    & $psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE $DbName TO $DbUser;" 2>$null
    Write-Ok "Database $DbName ready"
}

# ── 3. Virtual environment & dependencies ───────────────────────────────────
Write-Step "Python virtual environment"
$venvPath = Join-Path $Root ".venv"
$venvPython = Join-Path $venvPath "Scripts\python.exe"
if (-not (Test-Path $venvPython)) {
    python -m venv $venvPath
    Write-Ok "Created .venv"
}
if (-not $SkipPythonDeps) {
    Write-Step "Installing Python dependencies (may take several minutes)"
    & $venvPython -m pip install --upgrade pip -q
    & $venvPython -m pip install -r (Join-Path $Root "requirements.txt")
    if ($LASTEXITCODE -ne 0) { Write-Fail "pip install failed"; exit 1 }
    Write-Ok "Dependencies installed"
}

# ── 4. .env ─────────────────────────────────────────────────────────────────
Write-Step "Writing configuration (.env)"
$secret = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 48 | ForEach-Object { [char]$_ })
$dbUrl = "postgresql://${DbUser}:$DbPassword@127.0.0.1:5432/${DbName}"
$envContent = @"
DEPLOYMENT_MODE=local
ENVIRONMENT=production
DEBUG=False
DATABASE_URL=$dbUrl
SECRET_KEY=$secret
APP_HOST=0.0.0.0
APP_PORT=$Port
LICENSE_CLOUD_URL=$($CloudUrl.TrimEnd('/'))
LICENSE_ENFORCEMENT=true
LICENSE_REQUIRED_FOR_SETUP=true
ALLOW_LEGACY_UNLICENSED=false
LICENSE_ALLOW_OFFLINE_SETUP=false
REDIS_URL=redis://127.0.0.1:6379
CLOUD_SYNC_ENABLED=true
CLOUD_SYNC_REALTIME=true
CLOUD_SYNC_INTERVAL_SECONDS=30
AUTO_PROVISION_CLOUD_MIRROR=true
"@
Set-Content -Path (Join-Path $Root ".env") -Value $envContent -Encoding UTF8
Write-Ok ".env created"

# License node config for cloud heartbeat
$nodeConfig = @{
    cloud_url = $CloudUrl.TrimEnd('/')
    license_key = ""
    node_name = $env:COMPUTERNAME
    public_base_url = ""
    machine_fingerprint = ""
    node_id = ""
    sync_token = ""
} | ConvertTo-Json -Depth 3
$nodePath = Join-Path $Root "deploy\license-node.json"
if (-not (Test-Path (Split-Path $nodePath))) { New-Item -ItemType Directory -Force -Path (Split-Path $nodePath) | Out-Null }
Set-Content -Path $nodePath -Value $nodeConfig -Encoding UTF8
Write-Ok "deploy\license-node.json template (add license key after purchase)"

# ── 5. Database bootstrap ───────────────────────────────────────────────────
if (-not $SkipDbBootstrap) {
    Write-Step "Initializing database schema and system seeds"
    $env:LICENSE_CLOUD_URL = $CloudUrl.TrimEnd('/')
    & $venvPython (Join-Path $Root "scripts\bootstrap_local_install.py") --cloud-url $CloudUrl --port $Port
    if ($LASTEXITCODE -ne 0) {
        Write-Fail "Database bootstrap failed"
        exit 1
    }
}

# ── 6. Firewall ─────────────────────────────────────────────────────────────
if (-not $SkipFirewall) {
    Write-Step "Windows Firewall (port $Port for LAN)"
    try {
        $ruleName = "CNPERP Local ERP ($Port)"
        $existing = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
        if (-not $existing) {
            New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Protocol TCP -LocalPort $Port -Action Allow | Out-Null
            Write-Ok "Firewall rule added"
        } else {
            Write-Ok "Firewall rule already exists"
        }
    } catch {
        Write-Warn "Could not add firewall rule (run installer as Administrator)"
    }
}

# ── 7. Desktop shortcuts ────────────────────────────────────────────────────
if (-not $NoDesktopShortcut) {
    Write-Step "Desktop shortcuts"
    $startScript = Join-Path $Root "deploy\local-server\Start-CNPERP-Server.ps1"
    $icon = Join-Path $Root "app\static\icons\cnp-solutions-logo.ico"
    if (-not (Test-Path $icon)) {
        $icon = Join-Path $Root "app\static\icons\icon-192.png"
    }
    $pwsh = (Get-Command powershell).Source
    $cloudBase = $CloudUrl.TrimEnd('/')
    $loginPath = "/static/login.html?from=home"

    $lnk1 = New-DesktopShortcut -name "CNPERP Server" `
        -target $pwsh `
        -arguments "-NoExit -ExecutionPolicy Bypass -File `"$startScript`" -InstallRoot `"$Root`" -Port $Port" `
        -workingDir $Root `
        -iconPath $icon
    Write-Ok "CNPERP Server -> $lnk1"

    $lnk2 = New-DesktopShortcut -name "CNPERP Setup Wizard" `
        -target $pwsh `
        -arguments "-Command `"Start-Process 'http://localhost:$Port/setup'`"" `
        -workingDir $Root `
        -iconPath $icon
    Write-Ok "CNPERP Setup Wizard -> $lnk2"

    $urlLocal = New-InternetShortcutUrl -name "CNPERP Local ERP" `
        -url "http://localhost:$Port$loginPath" `
        -iconPath $icon
    Write-Ok "CNPERP Local ERP (login) -> $urlLocal"

    $urlCloud = New-InternetShortcutUrl -name "CNPERP Cloud ERP" `
        -url "$cloudBase$loginPath" `
        -iconPath $icon
    Write-Ok "CNPERP Cloud ERP (login) -> $urlCloud"
}

# ── Done ────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "=============================================" -ForegroundColor Green
Write-Host "  Installation complete" -ForegroundColor Green
Write-Host "=============================================" -ForegroundColor Green
Write-Host ""
Write-Host "  Next steps:" -ForegroundColor White
Write-Host "  1. Obtain a license key from: $CloudUrl" -ForegroundColor Gray
Write-Host "  2. Double-click 'CNPERP Server' on the desktop (keep window open)" -ForegroundColor Gray
Write-Host "  3. Open 'CNPERP Setup Wizard' — enter license, then company setup" -ForegroundColor Gray
Write-Host "  4. LAN users: http://<this-pc-ip>:$Port" -ForegroundColor Gray
Write-Host "  5. Cloud sync: LAN transactions push to $CloudUrl in near real time" -ForegroundColor Gray
Write-Host ""
Write-Host "  After setup: deploy\local-server\Connect-Cloud.ps1 (license in license-node.json)" -ForegroundColor Gray
Write-Host "  Optional heartbeat: deploy\setup_license_heartbeat_task.ps1" -ForegroundColor DarkGray
Write-Host ""

if ($LaunchSetup) {
    Start-Process "http://localhost:$Port/static/cnp-solutions.html"
}
