import 'express-async-errors';
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import rateLimit from 'express-rate-limit';
import { env } from './config/env';
import { logger } from './utils/logger';
import { errorHandler } from './middleware/error-handler';

// BigInt JSON serialization. Prisma's BigInt columns (e.g. Backup.sizeBytes)
// don't have a toJSON method by default, so res.json() throws. Stringify them.
(BigInt.prototype as unknown as { toJSON: () => string }).toJSON = function () {
  return this.toString();
};

// Route imports
import authRoutes from './modules/auth/auth.routes';
import instanceRoutes from './modules/instances/instances.routes';
import settingsRoutes from './modules/settings/settings.routes';
import healthRoutes from './modules/health/health.routes';
import auditRoutes from './modules/audit/audit.routes';
import backupRoutes from './modules/backups/backup.routes';
import eventsRoutes, { instanceEventsRouter } from './modules/events/events.routes';
import agentRoutes from './modules/agents/agents.routes';
import certificateRoutes from './modules/certificates/certificates.routes';
import inviteCodeRoutes from './modules/invite-codes/invite-codes.routes';
import { startHealthScheduler } from './services/health.service';
import { autoDiscoverOnStartup } from './services/discovery.service';

const app = express();

// Global middleware
app.use(helmet());
app.use(compression());
app.use(express.json({ limit: '10mb' }));
app.use(
  cors({
    origin: env.CORS_ORIGINS.split(',').map((s) => s.trim()),
    credentials: true,
  })
);

// Rate limiters
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 15,                   // 15 attempts per window
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: { message: 'Too many attempts, please try again later', code: 'RATE_LIMITED' } },
});

// Global API rate limiter — safety net against resource exhaustion
const apiLimiter = rateLimit({
  windowMs: 60 * 1000,      // 1 minute
  max: 300,                  // 300 req/min per IP (generous for a control panel)
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: { message: 'Too many requests, please try again later', code: 'RATE_LIMITED' } },
});

// Routes
app.use('/api', apiLimiter);
app.use('/api/auth', authLimiter, authRoutes);
app.use('/api/instances', instanceRoutes);
app.use('/api/settings', settingsRoutes);
app.use('/api/health', healthRoutes);
app.use('/api/audit', auditRoutes);
app.use('/api/backups', backupRoutes);
app.use('/api/events', eventsRoutes);
app.use('/api/instances/:id/events', instanceEventsRouter);
app.use('/api/agents', agentRoutes);
app.use('/api/certificates', certificateRoutes);
app.use('/api/invite-codes', inviteCodeRoutes);

// Error handler (must be last)
app.use(errorHandler);

app.listen(env.PORT, () => {
  logger.info(`CCP API listening on port ${env.PORT} (${env.NODE_ENV})`);
  startHealthScheduler(env.HEALTH_CHECK_INTERVAL_MS);

  // Auto-discover parent CML instance on first boot (5s delay for DB readiness)
  setTimeout(() => {
    autoDiscoverOnStartup().catch((err) =>
      logger.error(`[discovery] Auto-discovery failed: ${(err as Error).message}`)
    );
  }, 5_000);
});

export default app;
