'use strict';

const fs = require('fs');
const path = require('path');

// better-sqlite3's better_sqlite3.node is architecture-specific (it links
// against libnode.so, which is the real Android binary already loaded into
// this process by nodejs-mobile-cordova). The copy under node_modules/ is
// whichever architecture it happened to be built for last; replace it with
// the prebuild matching this device's actual arch before anything requires
// better-sqlite3. See scripts/build-better-sqlite3-node18.sh.
(function installBetterSqlite3Prebuild() {
  const archDirs = {
    arm64: 'arm64-v8a',
    arm: 'armeabi-v7a',
    x64: 'x86_64',
    ia32: 'x86',
  };
  const archDir = archDirs[process.arch];
  if (!archDir) return; // Unknown arch — fall back to whatever's bundled.

  const prebuilt = path.join(__dirname, 'prebuilds', archDir, 'better_sqlite3.node');
  const target = path.join(__dirname, 'node_modules', 'better-sqlite3', 'build', 'Release', 'better_sqlite3.node');
  if (!fs.existsSync(prebuilt)) return;

  try {
    fs.mkdirSync(path.dirname(target), { recursive: true });
    fs.copyFileSync(prebuilt, target);
  } catch (err) {
    console.error('[main.js] Failed to install better-sqlite3 prebuild for', process.arch, err);
  }
})();

// nodejs-mobile's Node 18.20.4 build ships WITHOUT ICU (verified:
// process.versions.icu === undefined, typeof Intl === 'undefined'), so `Intl`
// is entirely absent. Polyfill just the bits the server uses — en-US number
// formatting with thousands separators, and a no-op DateTimeFormat whose
// resolvedOptions().timeZone the callers already treat as optional.
//
// (crypto.randomUUID and crypto.hkdfSync are NATIVE on Node 18 — the Node-12
// shims for them are gone. See PLAN/FUTURE Batch 6.)
if (typeof global.Intl === 'undefined') {
  global.Intl = {
    NumberFormat: function (_locale, options) {
      const opts = options || {};
      const minFrac = opts.minimumFractionDigits || 0;
      const maxFrac = Math.max(opts.maximumFractionDigits || 0, minFrac);
      this.format = function (value) {
        const fixed = Number(value).toFixed(maxFrac);
        let [intPart, fracPart] = fixed.split('.');
        const negative = intPart.startsWith('-');
        if (negative) intPart = intPart.slice(1);
        intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        let out = (negative ? '-' : '') + intPart;
        if (fracPart) out += '.' + fracPart;
        return out;
      };
    },
    DateTimeFormat: function () {
      this.resolvedOptions = function () {
        return { timeZone: undefined };
      };
    },
  };
}

// Server-side paths, relative to this directory (the app's writable storage
// on-device — nodejs-mobile-cordova copies nodejs-project here at runtime).
process.env.DB_PATH = path.join(__dirname, 'data', 'bills.db');
process.env.BACKUP_PATH = path.join(__dirname, 'backups');
// Android has no /tmp; point os.tmpdir() at app-writable storage so the daily
// worker's temp-export cleanup doesn't error (ENOENT scandir '/tmp').
process.env.TMPDIR = path.join(__dirname, 'tmp');
try { fs.mkdirSync(process.env.TMPDIR, { recursive: true }); } catch (_) { /* best effort */ }
process.env.PORT = process.env.PORT || '3000';
process.env.BIND_HOST = '127.0.0.1';
// The Capacitor WebView's origin (androidScheme: 'https') is cross-origin
// from this server's http://localhost:3000, so the LoadingScreen's
// /api/health poll and the app's API calls need CORS allowed for it.
process.env.CORS_ORIGIN = 'https://localhost';

const cordova = require('cordova-bridge');

// Surface fatal errors to logcat and to the WebView (LoadingScreen) instead of
// dying silently behind an endless "Starting…" spinner.
function reportError(where, err) {
  const msg = err && err.stack ? err.stack : String(err);
  console.error('[main.js] ' + where + ':', msg);
  try {
    cordova.channel.post('message', { type: 'serverError', message: String((err && err.message) || err) });
  } catch (_) { /* channel may not be ready */ }
}

process.on('uncaughtException', (err) => reportError('uncaughtException', err));
process.on('unhandledRejection', (err) => reportError('unhandledRejection', err));

// Wait for the WebView to hand over the device-bound encryption key (stored in
// Android Keystore / iOS Keychain — see src/crypto.ts) before starting the
// server, so encryptionService picks up TOKEN_ENCRYPTION_KEY on first use.
cordova.channel.on('message', function (msg) {
  if (msg && msg.type === 'encryptionKey' && typeof msg.key === 'string') {
    process.env.TOKEN_ENCRYPTION_KEY = msg.key;
    try {
      require('./server/server.cts');
    } catch (err) {
      reportError('server failed to start', err);
    }
  }
});

cordova.channel.post('message', { type: 'ready' });
