@echo off
setlocal EnableDelayedExpansion
title URVault Server — Windows Installer

:: ============================================================
::  URVault Server — Windows Installer
::  Run as Administrator from the urvault-server\ folder
:: ============================================================

echo.
echo  ============================================================
echo   URVault Server - Windows Installer
echo  ============================================================
echo.

:: ── Admin check ─────────────────────────────────────────────
net session >nul 2>&1
if %errorLevel% neq 0 (
    echo  ERROR: This script must be run as Administrator.
    echo  Right-click install.bat and choose "Run as administrator".
    pause
    exit /b 1
)

:: ── Move to server root (script lives in install\windows\) ──
cd /d "%~dp0..\.."
echo  Working directory: %CD%
echo.

:: ── Node.js check ───────────────────────────────────────────
echo  [1/7] Checking prerequisites...
node --version >nul 2>&1
if %errorLevel% neq 0 (
    echo.
    echo  ERROR: Node.js not found.
    echo  Install Node.js 18+ from: https://nodejs.org/
    pause
    exit /b 1
)
for /f "tokens=1" %%v in ('node --version') do set NODE_VER=%%v
for /f "tokens=1 delims=." %%m in ("!NODE_VER:~1!") do set NODE_MAJOR=%%m
if !NODE_MAJOR! LSS 18 (
    echo  ERROR: Node.js 18+ required. Found: !NODE_VER!
    pause
    exit /b 1
)
echo  Node.js !NODE_VER! — OK

:: ── MySQL check ─────────────────────────────────────────────
mysql --version >nul 2>&1
if %errorLevel% neq 0 (
    echo.
    echo  ERROR: MySQL not found.
    echo  Install MySQL 8.0+ from: https://dev.mysql.com/downloads/mysql/
    pause
    exit /b 1
)
echo  MySQL — OK
echo.

:: ── Gather config ────────────────────────────────────────────
echo  [2/7] Gathering configuration...
echo.
set /p "MYSQL_ROOT_PW=  MySQL root password: "
echo.
set /p "DB_PASSWORD=  New password for URVault database user: "
echo.

:: Detect local IP (skip APIPA 169.x addresses)
for /f "tokens=2 delims=:" %%a in ('ipconfig ^| findstr /C:"IPv4 Address" ^| findstr /V "169.254"') do (
    set "RAW_IP=%%a"
    set "LOCAL_IP=!RAW_IP: =!"
    goto :ip_done
)
:ip_done
if not defined LOCAL_IP set LOCAL_IP=127.0.0.1
echo  Detected local IP: %LOCAL_IP%

:: Storage path -- Windows folder browser dialog
set "DEFAULT_STORAGE=C:\ProgramData\URVault\backups"
echo  Opening folder browser -- select your backup storage location.
echo  (Default: %DEFAULT_STORAGE%)
echo.

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
    "Add-Type -AssemblyName System.Windows.Forms; $d = New-Object System.Windows.Forms.FolderBrowserDialog; $d.Description = 'Browse and select storage drive or folder'; $d.SelectedPath = 'C:\ProgramData\URVault\backups'; $d.ShowNewFolderButton = $true; if ($d.ShowDialog() -eq 'OK') { $d.SelectedPath } else { 'C:\ProgramData\URVault\backups' }" ^
    > "%TEMP%\urvault_storage.txt" 2>nul

set /p "STORAGE_PATH=" < "%TEMP%\urvault_storage.txt"
del "%TEMP%\urvault_storage.txt" >nul 2>&1
if "!STORAGE_PATH!"=="" set STORAGE_PATH=%DEFAULT_STORAGE%
echo  Storage location: !STORAGE_PATH!
echo.

:: ── Generate secrets via Node.js ─────────────────────────────
echo  [3/7] Generating security keys...

:: Write a temporary secret-gen script
> "%TEMP%\urvault_gen.js" (
    echo const c = require^('crypto'^);
    echo const out = {
    echo   JWT_SECRET:      c.randomBytes^(32^).toString^('hex'^),
    echo   ENCRYPTION_KEY:  c.randomBytes^(32^).toString^('hex'^),
    echo   ADMIN_KEY:       c.randomBytes^(32^).toString^('hex'^),
    echo   MAILBOX_SECRET:  c.randomBytes^(32^).toString^('hex'^),
    echo   SERVER_UUID:     c.randomUUID^(^),
    echo };
    echo Object.entries^(out^).forEach^(([k,v]^) =^> console.log^(k + '=' + v^)^);
)

for /f "tokens=1,2 delims==" %%k in ('node "%TEMP%\urvault_gen.js"') do set %%k=%%l
del "%TEMP%\urvault_gen.js" >nul 2>&1

if not defined JWT_SECRET (
    echo  ERROR: Failed to generate secrets. Is Node.js working?
    pause
    exit /b 1
)
echo  Security keys generated — OK
echo.

:: ── Create directories ───────────────────────────────────────
echo  [4/7] Creating directories...
if not exist "C:\ProgramData\URVault" mkdir "C:\ProgramData\URVault"
if not exist "%STORAGE_PATH%" mkdir "%STORAGE_PATH%"
echo  Storage directory: %STORAGE_PATH%
echo.

:: ── Create database ──────────────────────────────────────────
echo  [5/7] Creating database...
mysql -u root -p%MYSQL_ROOT_PW% -e "CREATE DATABASE IF NOT EXISTS urvault; CREATE USER IF NOT EXISTS 'urvault'@'localhost' IDENTIFIED BY '%DB_PASSWORD%'; GRANT ALL PRIVILEGES ON urvault.* TO 'urvault'@'localhost'; FLUSH PRIVILEGES;" 2>&1
if %errorLevel% neq 0 (
    echo.
    echo  ERROR: Database setup failed. Check your MySQL root password and try again.
    pause
    exit /b 1
)
echo  Database created — OK
echo.

:: ── Write .env ───────────────────────────────────────────────
echo  Writing .env configuration...

:: Use Node.js to write .env cleanly (avoids batch escape issues with backslashes)
node -e "
const fs = require('fs');
const storagePath = '%STORAGE_PATH%'.replace(/\\\\/g, '\\\\\\\\');
const content = [
  '# URVault Configuration',
  '# Generated by installer on ' + new Date().toISOString(),
  '',
  '# Database',
  'DB_HOST=localhost',
  'DB_PORT=3306',
  'DB_USER=urvault',
  'DB_PASSWORD=%DB_PASSWORD%',
  'DB_NAME=urvault',
  '',
  '# Server',
  'PORT=5173',
  'SERVER_PORT=5173',
  'SERVER_HOST=0.0.0.0',
  'NODE_ENV=production',
  'HOST=0.0.0.0',
  '',
  '# Storage',
  'STORAGE_PATH=' + storagePath,
  'MAX_BACKUP_SIZE=10737418240',
  '',
  '# Security',
  'JWT_SECRET=%JWT_SECRET%',
  'ENCRYPTION_KEY=%ENCRYPTION_KEY%',
  'ADMIN_KEY=%ADMIN_KEY%',
  '',
  '# Relay',
  'MAILBOX_URL=https://urvault.net',
  'MAILBOX_SECRET=%MAILBOX_SECRET%',
  '',
  '# Network (LOCAL_IP updated automatically on each startup)',
  'LOCAL_IP=%LOCAL_IP%',
  '# EXTERNAL_URL is set automatically at startup via Cloudflare Tunnel',
  'EXTERNAL_URL=',
  'SERVER_UUID=%SERVER_UUID%',
].join('\r\n');
fs.writeFileSync('.env', content);
console.log('  .env written OK');
"
if %errorLevel% neq 0 (
    echo  ERROR: Failed to write .env
    pause
    exit /b 1
)

:: ── Run migrations ───────────────────────────────────────────
echo.
echo  Running database migrations...
node run-migrations.js
if %errorLevel% neq 0 (
    echo  WARNING: Migrations reported an error ^(may be OK if tables already exist^).
)
echo.

:: ── Download cloudflared ─────────────────────────────────────
echo  [6/7] Downloading remote access tunnel ^(cloudflared^)...
if exist cloudflared.exe (
    echo  cloudflared.exe already present — skipping download.
) else (
    powershell -NoProfile -ExecutionPolicy Bypass -Command ^
        "Invoke-WebRequest -Uri 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe' -OutFile 'cloudflared.exe'" 2>&1
    if exist cloudflared.exe (
        echo  cloudflared downloaded — remote access enabled.
    ) else (
        echo  WARNING: cloudflared download failed. Remote access will be unavailable.
        echo  You can download it manually from: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
    )
)
echo.

:: ── Create start-server.bat ──────────────────────────────────
echo  [7/7] Creating startup script...

:: Write the PowerShell tunnel watchdog helper
> "%TEMP%\urvault_write_startup.js" (
    echo const fs = require^('fs'^);
    echo.
    echo const ps = `
    echo param^([string]$Port, [string]$EnvFile^)
    echo while ^($true^) {
    echo     $log = [System.IO.Path]::GetTempFileName^(^)
    echo     $proc = Start-Process -FilePath '.\\cloudflared.exe' ``
    echo         -ArgumentList "tunnel --url http://localhost:$Port --no-autoupdate" ``
    echo         -RedirectStandardError $log -PassThru -NoNewWindow
    echo     $url = $null
    echo     for ^($i = 0; $i -lt 60; $i++^) {
    echo         Start-Sleep -Seconds 1
    echo         $txt = try { Get-Content $log -Raw -ErrorAction Stop } catch { '' }
    echo         if ^($txt -match 'https://[a-z0-9-]+\\.trycloudflare\\.com'^) {
    echo             $url = $Matches[0]; break
    echo         }
    echo     }
    echo     if ^($url^) {
    echo         $e = Get-Content $EnvFile -Raw
    echo         $e = $e -replace '(?m)^EXTERNAL_URL=.*', "EXTERNAL_URL=$url"
    echo         $e = $e -replace '(?m)^# EXTERNAL_URL=.*', "EXTERNAL_URL=$url"
    echo         Set-Content $EnvFile $e -NoNewline
    echo         Write-Host "Remote access URL: $url"
    echo         $lines = $e -split '\r?\n'
    echo         $mu = ^($lines ^| Where-Object { $_ -match '^MAILBOX_URL=' }^) -replace '^MAILBOX_URL=',''
    echo         $ms = ^($lines ^| Where-Object { $_ -match '^MAILBOX_SECRET=' }^) -replace '^MAILBOX_SECRET=',''
    echo         $su = ^($lines ^| Where-Object { $_ -match '^SERVER_UUID=' }^) -replace '^SERVER_UUID=',''
    echo         if ^($mu -and $ms -and $su^) {
    echo             $body = ConvertTo-Json @{ uuid=$su; url=$url; secret=$ms }
    echo             try { Invoke-RestMethod -Uri "$mu/api/register" -Method Post -Body $body -ContentType 'application/json' } catch {}
    echo         }
    echo     } else {
    echo         Write-Host 'Warning: Tunnel URL not detected - remote access unavailable this session.'
    echo     }
    echo     $proc ^| Wait-Process -ErrorAction SilentlyContinue
    echo     Remove-Item $log -ErrorAction SilentlyContinue
    echo     Write-Host 'Tunnel exited - restarting in 10s...'
    echo     Start-Sleep -Seconds 10
    echo }
    echo `;
    echo.
    echo const bat = `@echo off
    echo setlocal EnableDelayedExpansion
    echo cd /d "%~dp0"
    echo echo === URVault startup ===
    echo.
    echo :: Detect and update local IP
    echo for /f "tokens=2 delims=:" %%a in ('ipconfig ^| findstr /C:"IPv4 Address" ^| findstr /V "169.254"') do (
    echo     set "RAW=%%a"
    echo     set "CIP=!RAW: =!"
    echo     goto :ipfound
    echo )
    echo :ipfound
    echo if defined CIP (
    echo     node -e "try{const fs=require('fs');let e=fs.readFileSync('.env','utf8');e=e.replace(/^LOCAL_IP=.*/m,'LOCAL_IP=!CIP!');fs.writeFileSync('.env',e);}catch(e){}"
    echo     echo Local IP: !CIP!
    echo )
    echo.
    echo :: Read PORT from .env
    echo for /f "tokens=1,2 delims==" %%k in (.env) do if "%%k"=="PORT" set PORT=%%l
    echo if not defined PORT set PORT=5173
    echo.
    echo :: Start Cloudflare tunnel watchdog (remote access, no port forwarding)
    echo if exist cloudflared.exe (
    echo     echo Starting remote access tunnel...
    echo     start /B powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0tunnel-watchdog.ps1" -Port !PORT! -EnvFile "%~dp0.env"
    echo ) else (
    echo     echo cloudflared.exe not found - remote access unavailable.
    echo     echo Download from: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
    echo )
    echo.
    echo :: Run migrations
    echo echo Running database migrations...
    echo node run-migrations.js 2^>nul ^|^| echo Migrations skipped.
    echo echo.
    echo.
    echo :: Start server
    echo echo Starting server...
    echo node dist\\server.js
    echo `;
    echo.
    echo fs.writeFileSync^('start-server.bat', bat^);
    echo fs.writeFileSync^('tunnel-watchdog.ps1', ps^);
    echo console.log^('  Startup scripts written OK'^);
)

node "%TEMP%\urvault_write_startup.js"
del "%TEMP%\urvault_write_startup.js" >nul 2>&1

:: ── Firewall rule ────────────────────────────────────────────
netsh advfirewall firewall delete rule name="URVault Server" >nul 2>&1
netsh advfirewall firewall add rule name="URVault Server" dir=in action=allow protocol=TCP localport=5173 >nul 2>&1
echo  Firewall rule added for port 5173.

:: ── Optional: Windows service ────────────────────────────────
echo.
set /p "INSTALL_SVC=  Install URVault as a Windows service (auto-start on boot)? (y/n): "
if /i "!INSTALL_SVC!"=="y" (
    :: Create a VBScript wrapper so the service can run without a console window
    > "%TEMP%\urvault_svc.js" (
        echo const { execSync } = require^('child_process'^);
        echo const path = require^('path'^);
        echo const dir = path.resolve^(__dirname^);
        echo // Register using sc.exe with node as the binary
        echo // We use NSSM if available, otherwise advise manual setup
        echo try {
        echo   execSync^('where nssm', { stdio: 'ignore' }^);
        echo   execSync^(`nssm install URVault "${process.execPath}" "dist\\server.js"`, { cwd: dir, stdio: 'inherit' }^);
        echo   execSync^(`nssm set URVault AppDirectory "${dir}"`, { stdio: 'inherit' }^);
        echo   execSync^(`nssm set URVault DisplayName "URVault Server"`, { stdio: 'inherit' }^);
        echo   execSync^(`nssm set URVault Description "URVault personal cloud backup server"`, { stdio: 'inherit' }^);
        echo   execSync^(`nssm set URVault Start SERVICE_AUTO_START`, { stdio: 'inherit' }^);
        echo   execSync^(`nssm start URVault`, { stdio: 'inherit' }^);
        echo   console.log^('  Service installed and started via NSSM.'^);
        echo } catch ^(e^) {
        echo   console.log^('  NSSM not found. To auto-start URVault on boot:'^);
        echo   console.log^('  1. Download NSSM from https://nssm.cc/download'^);
        echo   console.log^('  2. Run: nssm install URVault node dist\\server.js'^);
        echo   console.log^('  Or add start-server.bat to Windows Task Scheduler.'^);
        echo }
    )
    node "%TEMP%\urvault_svc.js"
    del "%TEMP%\urvault_svc.js" >nul 2>&1
)

:: ── Done ─────────────────────────────────────────────────────
echo.
echo  ============================================================
echo   Installation Complete!
echo  ============================================================
echo.
echo   Local access:   http://%LOCAL_IP%:5173
echo   Admin setup:    http://localhost:5173
echo.
echo   To start the server:
echo     Double-click start-server.bat
echo     (or run it from this folder)
echo.
echo   Next steps:
echo     1. Run start-server.bat
echo     2. Open http://localhost:5173 in your browser
echo     3. Complete the setup wizard
echo     4. Pair your phone using the URVault app
echo.
echo   Backup files are stored in:
echo     %STORAGE_PATH%
echo   This folder is NOT removed if you uninstall the app files.
echo.
pause
