// chat-server — Phase 9 §9.1 of CONSOLIDATION_PLAN.md.
//
// ESM conversion + in-process authenticate() defense-in-depth. Previously this
// service relied on the Caddy `forward_auth` gate alone — `localhost:3014`
// was reachable unauthenticated. Now:
//   1. Bound to 127.0.0.1 (was 0.0.0.0) so direct-port access is impossible.
//   2. authenticate() runs against an in-process `inventory_db` pool before
//      any route handler sees the request.
//
// Two pools intentionally:
//   - `inventoryPool`: used by authenticate() for users/permissions lookups
//     against the main inventory_db (matches DB_* env vars).
//   - `pool` (set as global.pool for routes.js): the existing
//     `rocketchat_converted` pool driven by CHAT_DB_* env vars. routes.js
//     reads global.pool throughout — no handler-body changes needed.

import { config as loadEnv } from 'dotenv';
import express from 'express';
import cors from 'cors';
import morgan from 'morgan';
import pg from 'pg';
import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';

import { authenticate } from '../shared/auth/middleware.js';
import { corsOptions } from '../shared/cors/policy.js';
import { errorHandler } from '../shared/errors/handler.js';
import { requestLog } from '../shared/logging/request-log.js';

import chatRoutes from './routes.js';

const { Pool } = pg;
const __dirname = path.dirname(fileURLToPath(import.meta.url));

// Env layering matches dashboard-server (Deviation #18): shared .env wins on
// collisions for security-critical vars, local .env supplies CHAT_DB_*.
const sharedEnvPath = '/var/www/inventory/.env';
const localEnvPath = path.resolve(__dirname, '.env');
if (fs.existsSync(sharedEnvPath)) loadEnv({ path: sharedEnvPath });
if (fs.existsSync(localEnvPath)) loadEnv({ path: localEnvPath });

if (!process.env.JWT_SECRET) {
  console.error('JWT_SECRET is not set; refusing to start (per Phase 6.4)');
  process.exit(1);
}

const app = express();
const port = Number(process.env.CHAT_PORT) || 3014;

console.log('Starting chat server with config:', {
  host: process.env.CHAT_DB_HOST,
  user: process.env.CHAT_DB_USER,
  database: process.env.CHAT_DB_NAME || 'rocketchat_converted',
  port: process.env.CHAT_DB_PORT,
  chat_port: port,
});

// Rocket.Chat archive pool — routes.js reads it via global.pool.
const pool = new Pool({
  host: process.env.CHAT_DB_HOST,
  user: process.env.CHAT_DB_USER,
  password: process.env.CHAT_DB_PASSWORD,
  database: process.env.CHAT_DB_NAME || 'rocketchat_converted',
  port: process.env.CHAT_DB_PORT,
});
global.pool = pool;

// inventory_db pool — used by authenticate() for user/permission lookups.
const inventoryPool = new Pool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  port: Number(process.env.DB_PORT) || 5432,
  ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
});

app.use(requestLog());
app.use(express.json());
app.use(morgan('combined'));
app.use(cors(corsOptions));

// /health stays unauthenticated for out-of-band probes — mounted BEFORE
// authenticate() so monitoring tools on the host can poll without a JWT.
// Only reachable via localhost:3014 directly (Caddy routes /health to
// inventory-server:3010, not here).
app.get('/health', (req, res) => res.json({ status: 'healthy' }));

// Phase 9 §9.1 — per-server auth re-verification. Every chat route must pass
// authenticate() in addition to the Caddy forward_auth gate.
app.use(authenticate({ pool: inventoryPool, secret: process.env.JWT_SECRET }));

app.get('/test-db', async (req, res, next) => {
  try {
    const result = await pool.query('SELECT COUNT(*) as user_count FROM users WHERE active = true');
    const messageResult = await pool.query('SELECT COUNT(*) as message_count FROM message');
    const roomResult = await pool.query('SELECT COUNT(*) as room_count FROM room');
    res.json({
      status: 'success',
      database: 'rocketchat_converted',
      stats: {
        active_users: parseInt(result.rows[0].user_count, 10),
        total_messages: parseInt(messageResult.rows[0].message_count, 10),
        total_rooms: parseInt(roomResult.rows[0].room_count, 10),
      },
    });
  } catch (err) {
    next(err);
  }
});

app.use('/', chatRoutes);

app.use(errorHandler);

// Phase 9 §9.1 — bind to 127.0.0.1. Caddy reverse_proxy targets localhost:3014
// already; this closes the gap where unauthenticated direct-port access from
// any host on the network was possible.
const server = app.listen(port, '127.0.0.1', () => {
  console.log(`Chat server running on 127.0.0.1:${port}`);
});

const shutdown = async (signal) => {
  console.log(`chat-server shutting down (${signal})`);
  server.close();
  try { await pool.end(); } catch { /* ignore */ }
  try { await inventoryPool.end(); } catch { /* ignore */ }
  process.exit(0);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
