// Load .env FIRST, before any import below reads process.env at module-load
// time (e.g. config/database reads DATABASE_URL, config/mailer reads MAIL_*).
// The dev script preloads this via `-r dotenv/config`, but the production
// entrypoint (`node dist/server.js`) does not — without this line the built
// server ignores .env entirely and only sees the OS/process-manager env.
import 'dotenv/config';

import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import path from 'path';
import { createServer } from 'http';
import { Server } from 'socket.io';
import authRoutes from './routes/auth.routes';
import visitorRoutes from './routes/visitors.routes';
import visitorScannerRoutes from './routes/visitor-scanner.routes';
import approverRoutes from './routes/approver.routes';
import departmentsRoutes from './routes/departments.routes';
import emailTemplatesRoutes from './routes/emailTemplates.routes';
import emailAutomationRoutes from './routes/emailAutomation.routes';
import whatsAppTemplatesRoutes from './routes/whatsAppTemplates.routes';
import whatsAppAutomationRoutes from './routes/whatsAppAutomation.routes';
import automationTimingsRoutes from './routes/automationTimings.routes';
import photoCaptureSettingsRoutes from './routes/photoCaptureSettings.routes';
import pushSubscriptionRoutes from './routes/pushSubscription.routes';
import platformRoutes from './routes/platform.routes';
import { walkInQRRoutes, publicWalkInRoutes } from './routes/walkInQR.routes';
import decisionRoutes from './routes/decision.routes';
import publicQrRoutes from './routes/publicQr.routes';
import { startVisitReminderCron } from './lib/reminderCron';
import { errorHandler } from './middleware/errorHandler';
import { rewriteUploadUrlsMiddleware } from './lib/publicUrl';

const app = express();
const httpServer = createServer(app);

// In production we sit behind a reverse proxy (Cloudflare / nginx / etc.).
// Trust the proxy so `req.protocol` follows X-Forwarded-Proto and our
// derived public URLs (saveUpload, walk-in QR generation) point at the real
// HTTPS host rather than the upstream HTTP one.
app.set('trust proxy', true);

const rawFrontendUrl = process.env.FRONTEND_URL || 'http://localhost:3200';
const corsOrigin = rawFrontendUrl === '*'
  ? true
  : rawFrontendUrl.split(',').map((s) => s.trim());

export const io = new Server(httpServer, {
  cors: { origin: corsOrigin, credentials: true },
});

app.use(helmet({ crossOriginResourcePolicy: { policy: 'cross-origin' } }));
app.use(cors({ origin: corsOrigin, credentials: true }));
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));

// Serve uploads under both `/uploads` and `/api/uploads`. The `/api/uploads`
// alias matters in production where the reverse proxy only routes `/api/*`
// to Node — without it, image URLs fall into the web SPA's catch-all and
// return HTML. The rewrite middleware below now emits the `/api/uploads/`
// prefix so old DB rows still resolve correctly under either deployment.
const uploadsDir = path.join(__dirname, '..', 'uploads');
app.use('/uploads', express.static(uploadsDir));
app.use('/api/uploads', express.static(uploadsDir));

// Auto-rewrites any '/uploads/...' string in API JSON responses to an
// absolute URL derived from the current request. Old rows in the DB still
// have relative paths stored; this middleware makes them resolve correctly
// from any web origin without a SQL backfill.
app.use(rewriteUploadUrlsMiddleware);

app.use('/api/auth', authRoutes);
app.use('/api/visitors', visitorRoutes);
app.use('/api/visitor-scanner', visitorScannerRoutes);
app.use('/api/approver', approverRoutes);
app.use('/api/departments', departmentsRoutes);
app.use('/api/email-templates', emailTemplatesRoutes);
app.use('/api/email-automation', emailAutomationRoutes);
app.use('/api/whatsapp-templates', whatsAppTemplatesRoutes);
app.use('/api/whatsapp-automation', whatsAppAutomationRoutes);
app.use('/api/automation-timings', automationTimingsRoutes);
app.use('/api/photo-capture-settings', photoCaptureSettingsRoutes);
app.use('/api/push', pushSubscriptionRoutes);
app.use('/api/platform', platformRoutes);
app.use('/api/walk-in-qrs', walkInQRRoutes);
app.use('/api/walk-in', publicWalkInRoutes);
app.use('/api/public/decision', decisionRoutes);
app.use('/api/public/qr', publicQrRoutes);

app.get('/api/health', (_req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

app.use(errorHandler);

io.on('connection', (socket) => {
  socket.on('join', (room: string) => socket.join(room));
  socket.on('leave', (room: string) => socket.leave(room));
});

const PORT = process.env.PORT || 4200;
httpServer.listen(PORT, () => {
  console.log(`Visitor API running on port ${PORT}`);
  // Kick off the visit-reminder cron. No-op when there are no visitors
  // in the ~24h window, so it's safe to run unconditionally.
  startVisitReminderCron();
});
