// BizGaze Connect — backend entry point.
// Thin wiring layer: HTTP request dispatch + WebSocket attach + listeners.
// All logic lives in focused modules:
//   repos.js      data-access (all SQL)
//   bizgaze.js    BizGaze identity provider
//   lib.js        HTTP helpers (json/readBody/parseCookies/now)
//   session.js    currentUser / audit
//   presence.js   shared in-memory live state (agents/sessions/shares)
//   routes.js     HTTP JSON API (/api/*, /sso)
//   static.js     static files + authenticated downloads (GET fallback)
//   signaling.js  WebSocket signaling (consent + SDP/ICE relay)
const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const { WebSocketServer } = require('ws');
const { PORT, HTTPS_PORT } = require('./config');
const { json } = require('./lib');
const routes = require('./routes');
const { handleGet } = require('./static');
const { onConnection } = require('./signaling');

// ---------- HTTP request dispatch ----------
const server = http.createServer((req, res) => {
  const key = `${req.method} ${req.url.split('?')[0]}`;
  // Route/static handlers are async now (DB adapter). Catch any rejection so a handler error becomes a
  // 500 instead of a hung request + unhandled promise rejection.
  let p;
  if (routes[key]) p = routes[key](req, res);
  else if (req.method === 'GET') p = handleGet(req, res); // downloads + static
  else return json(res, 404, { error: 'not found' });
  if (p && typeof p.catch === 'function') p.catch((e) => { try { console.error('handler error', key, e && e.message); json(res, 500, { error: 'server error' }); } catch (_) {} });
});

// ---------- WebSocket signaling ----------
const wss = new WebSocketServer({ server, path: '/ws' });
wss.on('connection', onConnection);

// Apply the DB schema BEFORE serving. For Postgres this creates the tables (async); for SQLite it's a
// no-op (the schema is already applied synchronously when db.js is required). Serving only starts once the
// store is ready, so the first request can never hit a missing table.
const db = require('./dbx');
const pubsub = require('./pubsub');

function startListening() {
  server.listen(PORT, () => {
    console.log(`HTTP  on http://localhost:${PORT}  (db=${db.name})`);
    try { require('./media').backfill(); } catch (e) {} // streaming renditions for older video uploads
  });

  // HTTPS — required so other devices can share their screen (browsers block
  // screen capture on non-secure origins). Uses cert.pem/key.pem if present.
  try {
    const certPath = path.join(__dirname, 'cert.pem');
    const keyPath = path.join(__dirname, 'key.pem');
    if (fs.existsSync(certPath) && fs.existsSync(keyPath)) {
      const httpsServer = https.createServer(
        { cert: fs.readFileSync(certPath), key: fs.readFileSync(keyPath) },
        (req, res) => server.emit('request', req, res)
      );
      const wssSecure = new WebSocketServer({ server: httpsServer, path: '/ws' });
      wssSecure.on('connection', onConnection);
      httpsServer.listen(HTTPS_PORT, () => {
        console.log(`HTTPS on https://localhost:${HTTPS_PORT}  (use this address from other devices)`);
        console.log(`  End user shares screen:   https://<this-pc-ip>:${HTTPS_PORT}/share`);
        console.log(`  Technician connects:      https://<this-pc-ip>:${HTTPS_PORT}/connect`);
      });
    } else {
      console.log('(No cert.pem/key.pem found — HTTPS disabled. Other devices can view but not share their screen.)');
    }
  } catch (e) {
    console.log('HTTPS failed to start:', e.message);
  }
}

// DB schema first, then the pub/sub layer (redis connects + flushes buffered subscriptions; memory is a
// no-op), then serve. A pubsub failure must NOT block booting — degrade to local-only delivery.
db.init()
  .then(() => pubsub.init().catch((e) => console.error('pubsub init failed (local-only delivery):', (e && e.message) || e)))
  .then(startListening)
  .catch((e) => { console.error('DB init failed:', (e && e.message) || e); process.exit(1); });

module.exports = { server };
