/* eslint-disable @typescript-eslint/no-explicit-any */

import express, { Express } from 'express';
// import helmet from 'helmet';
// import ExpressMongoSanitize from 'express-mongo-sanitize';
import compression from 'compression';
import cors from 'cors';
import passport from 'passport';
import httpStatus from 'http-status';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter.js';
import { authLimiter } from '@/shared/utils/index.js';
import {
  ApiError,
  errorConverter,
  errorHandler,
} from '@/shared/utils/errors/index.js';
import jwtStrategy from '@/shared/config/passport.js';
import config from '@/shared/config/config.js';
import routes from '@/routes/index.js';
import { ExpressAdapter } from '@bull-board/express';
import { createBullBoard } from '@bull-board/api';
import { NotificationQueue } from '@/jobs/notifications/notification.job.js';
import { successResponseMiddleware } from '@/shared/utils/middlewares/success.middleware.js';
import { initCronJobs } from './jobs/cron';
import publicRoutes from './routes/publicRoutes';
import { corsOptions } from './shared/config/cors';

const app: Express = express();

// set security HTTP headers
// app.use(helmet());

// enable cors
app.use(cors(corsOptions));

// parse json request body
app.use(
  express.json({
    limit: '20mb',
    verify: (req, _res, buf) => {
      (req as any).rawBody = buf.toString('utf8');
    },
  }),
);

// parse urlencoded request body
app.use(express.urlencoded({ limit: '20mb', extended: true }));

// sanitize request data
// app.use(ExpressMongoSanitize());

// gzip compression
app.use(compression());

app.use(successResponseMiddleware);

// Maintenance mode middleware
app.use((_req, res, next) => {
  const isMaintenanceMode = config.maintenanceMode === true;
  if (isMaintenanceMode) {
    res.status(503).json({
      code: 503,
      data: { maintenanceMode: isMaintenanceMode },
      message: 'We are under maintenance.',
    });
    return;
  }
  next();
});

// jwt authentication
app.use(passport.initialize());
passport.use('jwt', jwtStrategy);

// limit repeated failed requests to auth endpoints
if (config.env === 'production') app.use('/v1/auth', authLimiter);

const serverAdapter = new ExpressAdapter();
serverAdapter.setBasePath('/admin/queues');

createBullBoard({
  queues: [new BullMQAdapter(NotificationQueue)],
  serverAdapter,
});

// Register cron jobs only if this instance is scheduler
if (process.env.ROLE === 'scheduler') initCronJobs();

app.use('/admin/queues', serverAdapter.getRouter());

app.get('/', (_req, res) => {
  res.status(200).send('Welcome to the API!!');
});

// health check
app.get('/health', (_req, res) => {
  res.status(200).send('Makanify API is running!!!');
});

// v1 api routes
app.use('/api/v1', routes);

app.use('/webhook', publicRoutes);

// send back a 404 error for any unknown api request
app.use((_req, _res, next) => {
  next(new ApiError(httpStatus.NOT_FOUND, 'Not found'));
});

// Limit repeated failed requests to auth endpoints
if (config.env === 'production') app.use(authLimiter);

// convert error to ApiError, if needed
app.use(errorConverter);

// handle error
app.use(errorHandler);

export default app;
