@echo off
REM ===========================================================================
REM  D&D Docket - INSTALLER
REM
REM  Double-click this on the ONE computer that will hold the firm's register.
REM  It does the whole job, in order, and says what it is doing:
REM
REM    1. Node.js          checks for it, and offers to install it
REM    2. the program      downloads what it needs, compiles it
REM    3. the register     loads MainDB.xlsx, or keeps the one already here
REM    4. the server       firewall, start at boot, no sleeping, daily backup
REM    5. the icons        D&D Docket and D&D Invoices on this desktop
REM    6. a check          proves it is actually answering before it finishes
REM
REM  Safe to run again. It never overwrites a register that is already here,
REM  and every step checks whether it has already been done.
REM
REM  EVERYONE ELSE runs nothing. They open a browser at the address this
REM  prints, or get an icon from MAKE-DESKTOP-ICON.cmd. Only one computer may
REM  serve a given register - two would corrupt it.
REM ===========================================================================
setlocal EnableDelayedExpansion
cd /d "%~dp0"
title D^&D Docket - Installer
color 07

set "PORT=8787"
set "BILLING_PORT=8788"
set "HERE=%~dp0"
if "%HERE:~-1%"=="\" set "HERE=%HERE:~0,-1%"

cls
echo.
echo   =====================================================================
echo                      D^&D Docket - Installer
echo   =====================================================================
echo.
echo    Installing into:  %HERE%
echo.

REM --- administrator? ------------------------------------------------------
REM  Steps 4 and 5 need it. Rather than telling somebody to go away and
REM  right-click, ask Windows to re-launch this with the rights it needs.
net session >nul 2>nul
if errorlevel 1 (
  echo    This needs administrator rights to open the firewall and to start
  echo    the docket when the computer starts.
  echo.
  echo    Asking Windows for them now - say Yes to the prompt.
  echo.
  powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs" >nul 2>nul
  if errorlevel 1 (
    echo    That did not work. Close this window, right-click INSTALL.cmd and
    echo    choose "Run as administrator".
    echo.
    pause
  )
  exit /b 0
)

if not exist "package.json" (
  echo    This is not the docket folder - package.json is missing.
  echo    Run INSTALL.cmd from inside the folder you copied across.
  echo.
  pause
  exit /b 1
)

REM --- 1. Node -------------------------------------------------------------
echo   ---------------------------------------------------------------------
echo    [1 of 6]  Node.js
echo   ---------------------------------------------------------------------
where node >nul 2>nul
if not errorlevel 1 goto :node_ok

echo    Not installed. The docket needs it.
echo.
where winget >nul 2>nul
if errorlevel 1 goto :node_manual

echo    Installing it now from Microsoft's package manager. This takes a
echo    couple of minutes and needs the internet.
echo.
winget install --id OpenJS.NodeJS.LTS -e --accept-source-agreements --accept-package-agreements --silent
REM  winget puts node on the PATH for NEW processes, not for this one, so look
REM  for it where it lands rather than trusting the PATH we started with.
set "PATH=%PATH%;%ProgramFiles%\nodejs;%ProgramFiles(x86)%\nodejs"
where node >nul 2>nul
if not errorlevel 1 goto :node_ok

:node_manual
echo.
echo    Node.js could not be installed automatically.
echo.
echo    Install the LTS version by hand from  https://nodejs.org
echo    then run INSTALL.cmd again. Nothing else here needs the internet.
echo.
start https://nodejs.org
pause
exit /b 1

:node_ok
for /f "delims=" %%v in ('node --version') do set "NODEVER=%%v"
REM  Node 20 is the floor: the server uses features below that version which
REM  simply are not there, and the failure is a confusing stack trace rather
REM  than a clear message.
for /f "tokens=1 delims=." %%a in ("%NODEVER:v=%") do set "NODEMAJOR=%%a"
if %NODEMAJOR% LSS 20 (
  echo    Found Node %NODEVER%, which is too old - the docket needs 20 or newer.
  echo    Install the current LTS from https://nodejs.org and run this again.
  echo.
  start https://nodejs.org
  pause
  exit /b 1
)
echo    Node %NODEVER% - good.
echo.

REM --- 2. the program ------------------------------------------------------
echo   ---------------------------------------------------------------------
echo    [2 of 6]  The program
echo   ---------------------------------------------------------------------
echo    Downloading what it needs. A minute or so, and the only step that
echo    needs the internet - nothing after this does, ever.
echo.
call npm install --no-audit --no-fund --loglevel=error
if errorlevel 1 (
  echo.
  echo    That failed. The usual cause is no internet connection.
  echo    Check it and run INSTALL.cmd again.
  echo.
  pause
  exit /b 1
)
REM  dist\ is deliberately not copied between machines - it is compiled for
REM  the processor and Node version of the computer it was built on. Skipping
REM  this is what makes a fresh copy die with "Cannot find module".
echo    Compiling...
call npm run build
if errorlevel 1 (
  echo.
  echo    The program did not compile. Nothing will run until that is sorted.
  echo.
  pause
  exit /b 1
)
echo    Ready.
echo.

REM --- 3. the register -----------------------------------------------------
echo   ---------------------------------------------------------------------
echo    [3 of 6]  The register
echo   ---------------------------------------------------------------------
if exist "data\docket.sqlite" (
  for /f "delims=" %%n in ('node -e "try{const d=require('./node_modules/better-sqlite3')('data/docket.sqlite',{readonly:true});console.log(d.prepare('SELECT COUNT(*) c FROM application').get().c)}catch(e){console.log('?')}"') do set "APPS=%%n"
  echo    A register is already here - !APPS! trademark applications.
  echo    Leaving it exactly as it is.
  echo.
  goto :register_done
)

REM  Asked, never assumed. A spreadsheet sitting beside the folder used to be
REM  loaded without a word, which is exactly wrong for a fresh installation:
REM  the firm asked for a clean copy and would have got every old record back.
set "XLSX="
set "FOUND="
if exist "MainDB.xlsx" set "FOUND=MainDB.xlsx"
if exist "..\MainDB.xlsx" set "FOUND=..\MainDB.xlsx"

if defined FOUND (
  echo    No register here yet. %FOUND% was found beside this folder.
  echo.
  echo      Y  Load it - every trademark in the spreadsheet comes in
  echo      N  Start empty - a clean register with no records at all
  echo.
  set /p "LOADIT=   Load the spreadsheet? [Y/N]: "
)
if defined FOUND if /i "%LOADIT%"=="Y" set "XLSX=%FOUND%"

if not defined FOUND (
  echo    No register here yet, and MainDB.xlsx was not found beside this
  echo    folder.
  echo.
  set /p "XLSX=   Full path to MainDB.xlsx, or press Enter to start empty: "
)

if "%XLSX%"=="" (
  echo.
  echo    Starting empty. The spreadsheet can be loaded later with:
  echo        npm run import -- "C:\path\to\MainDB.xlsx"
  echo.
  call npm run --silent migrate
  goto :register_done
)

echo    Loading %XLSX% ...
call npm run import -- "%XLSX%"
if errorlevel 1 (
  echo.
  echo    The import did not finish. Check the path and run INSTALL.cmd again.
  echo.
  pause
  exit /b 1
)

:register_done

REM --- 4. this computer serves it ------------------------------------------
echo   ---------------------------------------------------------------------
echo    [4 of 6]  Setting this computer up to serve the docket
echo   ---------------------------------------------------------------------

echo     - opening the firewall on %PORT% and %BILLING_PORT%
powershell -NoProfile -Command ^
  "Remove-NetFirewallRule -DisplayName 'D&D Docket' -ErrorAction SilentlyContinue;" ^
  "New-NetFirewallRule -DisplayName 'D&D Docket' -Direction Inbound -Protocol TCP -LocalPort %PORT%,%BILLING_PORT% -Action Allow -Profile Private,Domain | Out-Null" >nul 2>nul
if errorlevel 1 (echo       could not - add it by hand, see docs\INSTALL.md) else (echo       done, on private and domain networks)

REM  "Run whether anyone is logged on or not" is what makes this behave like
REM  installed software: no black window for somebody to close by accident.
echo     - starting the docket when the computer starts
schtasks /delete /tn "D&D Docket" /f >nul 2>nul
schtasks /create /tn "D&D Docket" ^
  /tr "\"%SystemRoot%\System32\cmd.exe\" /c cd /d \"%HERE%\" ^& npm start" ^
  /sc onstart /ru SYSTEM /rl highest /f >nul 2>nul
if errorlevel 1 (echo       could not - see docs\INSTALL.md) else (echo       done, with no window to close)

echo     - stopping this computer going to sleep
powercfg /change standby-timeout-ac 0 >nul 2>nul
powercfg /change hibernate-timeout-ac 0 >nul 2>nul
powercfg /change monitor-timeout-ac 15 >nul 2>nul
echo       done, the screen still sleeps but the computer does not

echo     - scheduling the daily backup for 15:00
schtasks /delete /tn "D&D Docket backup" /f >nul 2>nul
schtasks /create /tn "D&D Docket backup" /tr "\"%HERE%\BACKUP.cmd\" /quiet" ^
  /sc daily /st 15:00 /ru SYSTEM /rl highest /f >nul 2>nul
if errorlevel 1 (echo       could not - run BACKUP.cmd by hand) else (echo       done, into backups\)

REM  Run it once, now. A backup that is only scheduled is a backup nobody
REM  has ever seen work: this task pointed at a BACKUP.cmd that did not
REM  exist, and failed silently every afternoon for months, because that is
REM  what a scheduled task does when it cannot find its program. Proving it
REM  here means a broken backup is found on the day it is installed.
echo     - taking one backup now, to prove it works
call "%HERE%\BACKUP.cmd" /quiet >nul 2>nul
if errorlevel 1 (
  echo       IT DID NOT WORK. Run BACKUP.cmd by hand to see why - until that
  echo       is sorted this computer has no backup.
) else (
  echo       done, and the 15:00 one runs exactly the same way
)
echo.

REM --- 5. icons on this desktop --------------------------------------------
echo   ---------------------------------------------------------------------
echo    [5 of 6]  Icons on this desktop
echo   ---------------------------------------------------------------------
REM  Edge with --app= opens a window with no address bar and no tabs, so the
REM  docket looks like a program rather than a web page. Edge is on every
REM  Windows 10 and 11 machine, so there is nothing to install. Same search
REM  order as MAKE-DESKTOP-ICON.cmd, which is what everybody else runs.
set "BROWSER="
for %%P in (
  "%ProgramFiles(x86)%\Microsoft\Edge\Application\msedge.exe"
  "%ProgramFiles%\Microsoft\Edge\Application\msedge.exe"
  "%ProgramFiles%\Google\Chrome\Application\chrome.exe"
  "%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe"
) do if not defined BROWSER if exist %%P set "BROWSER=%%~P"

set "ICON=%HERE%\web\docket.ico"
if not exist "%ICON%" set "ICON=%BROWSER%,0"

if not defined BROWSER (
  echo       no Edge or Chrome here, which is unusual - open
  echo       http://localhost:%PORT% in whatever browser it has
) else (
  call :shortcut "D&D Docket" "http://localhost:%PORT%/"
  call :shortcut "D&D Invoices" "http://localhost:%BILLING_PORT%/"
  echo       done - "D^&D Docket" and "D^&D Invoices" on this desktop
)
echo.
REM --- 6. does it actually answer? -----------------------------------------
echo   ---------------------------------------------------------------------
echo    [6 of 6]  Checking it works
echo   ---------------------------------------------------------------------
schtasks /run /tn "D&D Docket" >nul 2>nul
echo    Starting it and waiting for an answer...
REM  One PowerShell for the whole wait, not fifteen. Each start-up costs a
REM  second or two on its own, which is why a 2-second timeout in a loop that
REM  respawned every attempt could fail every single time against a docket
REM  that was running perfectly well.
REM
REM  Fifteen tries, so a docket that is never going to answer says so inside
REM  about a minute. It normally answers in ten seconds; one that has not
REM  after a minute has something wrong that waiting will not fix.
set "LIVE="
powershell -NoProfile -Command ^
  "for ($i=0; $i -lt 15; $i++) {" ^
  "  try { $null = Invoke-WebRequest -UseBasicParsing -Uri 'http://127.0.0.1:%PORT%/api/health' -TimeoutSec 3; exit 0 } catch { Start-Sleep -Seconds 2 } }" ^
  "exit 1"
if not errorlevel 1 set "LIVE=1"

if not defined LIVE (
  echo.
  echo    It is not answering yet.
  echo.
  echo    Run START-DOCKET.cmd to watch it start and see what it says. The
  echo    install itself finished - this is the last check, not a step.
  echo.
  pause
  exit /b 1
)
echo    It is running.
echo.

REM --- the addresses -------------------------------------------------------
cls
echo.
echo   =====================================================================
echo                       Installed and running
echo   =====================================================================
echo.
echo    On this computer
echo        Docket     http://localhost:%PORT%
echo        Invoices   http://localhost:%BILLING_PORT%
echo.
echo    For everybody else, hand out:
for /f "tokens=*" %%A in ('powershell -NoProfile -Command ^
  "Get-NetIPAddress -AddressFamily IPv4 ^| Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' } ^| ForEach-Object { $_.IPAddress }"') do (
  echo        http://%%A:%PORT%
)
echo.
echo    On each of their computers, run MAKE-DESKTOP-ICON.cmd and paste that
echo    address in. They install nothing.
echo.
echo   ---------------------------------------------------------------------
echo    First time in: the first person to open it creates the first account,
echo    and that account is a partner. Everyone else is added from the Users
echo    page inside the app.
echo.
echo    Two things this installer cannot do for you:
echo.
echo      * Ask whoever runs your network for a FIXED address for this
echo        computer. If it changes, everyone's icon stops working.
echo.
echo      * Copy the backups\ folder off this computer every week. A backup
echo        on the same disk does not survive the disk failing.
echo.
echo    The full guide, in English and Bangla, is GUIDE.html in this folder.
echo   ---------------------------------------------------------------------
echo.
pause
exit /b 0

REM --- one desktop shortcut, opened as its own app window ------------------
:shortcut
powershell -NoProfile -Command ^
  "$name = '%~1';" ^
  "$s = (New-Object -ComObject WScript.Shell).CreateShortcut([Environment]::GetFolderPath('Desktop') + '\' + $name + '.lnk');" ^
  "$s.TargetPath = '%BROWSER%';" ^
  "$s.Arguments  = '--app=%~2';" ^
  "$s.IconLocation = '%ICON%';" ^
  "$s.Description = 'Doulah and Doulah';" ^
  "$s.Save()" >nul 2>nul
exit /b 0
