const express = require('express');
const { registerAllModels } = require('./models/registerAll');

registerAllModels();

const cors = require('cors');
const compression = require('compression');
const rateLimit = require('express-rate-limit');

const cookieParser = require('cookie-parser');
const { getRuntimeConfig, loadEnv } = require('./config/env');

const coreAuthRouter = require('./routes/coreRoutes/coreAuth');
const coreApiRouter = require('./routes/coreRoutes/coreApi');
const coreDownloadRouter = require('./routes/coreRoutes/coreDownloadRouter');
const corePublicRouter = require('./routes/coreRoutes/corePublicRouter');
const adminAuth = require('./controllers/coreControllers/adminAuth');
const { tenantResolver, rbacMiddleware } = require('./middlewares/platform');

const errorHandlers = require('./handlers/errorHandlers');
const erpApiRouter = require('./routes/appRoutes/appApi');

const fileUpload = require('express-fileupload');
loadEnv();
const runtime = getRuntimeConfig(process.env);
// create our Express app
const app = express();

if (runtime.trustProxy) {
  app.set('trust proxy', 1);
}

app.disable('x-powered-by');
app.use((req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
  res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
  if (runtime.isProduction) {
    res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  }
  next();
});

app.use(
  cors({
    origin(origin, callback) {
      if (!origin) return callback(null, true);
      if (!runtime.isProduction) return callback(null, true);
      if (runtime.corsAllowedOrigins.includes(origin)) return callback(null, true);
      return callback(new Error('Origin not allowed by CORS'));
    },
    credentials: true,
  })
);

app.use(cookieParser());
app.use(express.json({ limit: runtime.jsonLimit }));
app.use(express.urlencoded({ extended: true, limit: runtime.urlencodedLimit }));

app.use(compression());

const authLimiter = rateLimit({
  windowMs: runtime.authWindowMs,
  max: runtime.authMax,
  standardHeaders: true,
  legacyHeaders: false,
  message: {
    success: false,
    result: null,
    message: 'Too many authentication attempts. Please try again later.',
  },
});

const apiLimiter = rateLimit({
  windowMs: runtime.apiWindowMs,
  max: runtime.apiMax,
  standardHeaders: true,
  legacyHeaders: false,
  skip: (req) => req.path === '/healthz',
  message: {
    success: false,
    result: null,
    message: 'Too many requests. Please slow down and try again shortly.',
  },
});

// // default options
// app.use(fileUpload());

// Here our API Routes
app.get('/healthz', (_req, res) =>
  res.status(200).json({
    success: true,
    result: { status: 'ok', environment: runtime.nodeEnv },
    message: 'Service healthy',
  })
);

app.use('/api', apiLimiter);
app.use('/api', authLimiter, coreAuthRouter);
app.use('/api', adminAuth.isValidAuthToken, tenantResolver, coreApiRouter);
app.use('/api', adminAuth.isValidAuthToken, tenantResolver, rbacMiddleware, erpApiRouter);
app.use('/download', coreDownloadRouter);
app.use('/public', corePublicRouter);

// If that above routes didnt work, we 404 them and forward to error handler
app.use(errorHandlers.notFound);

// production error handler
app.use(errorHandlers.productionErrors);

// done! we export it so we can start the site in start.js
module.exports = app;
