import express, { Response } from "express";
import logger from "./libs/logger";
import bodyParser from "body-parser";
import Session from "express-session";
import RedisStore from "connect-redis";
import Redis from "ioredis";
import injectRequest from "./middleware/injectRequest";
import helmet from "helmet";
import { AppConfig } from "./libs/config";
import injectValidateFormRequest from "./middleware/injectValidateFormRequest";
import { formValidationRules } from "./libs/formValidationRules";
import { setupRoutes } from "./libs/setupRoutes";
import nunjucks from "nunjucks";
import { errorHandlerMiddleware } from "./middleware/globalErrorHandler";
import { CustomError } from "./types/custom";
import { NextFunction } from "connect";
import { Request } from "express-serve-static-core";
import navigator from "./libs/navigator";
import path from "path";
import csrf from "csurf";
import cookieParser from "cookie-parser";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getApp = (config: AppConfig): any => {
  const app = express();

  const nunjucksConfig = nunjucks.configure(
    [
      "routes",
      "views",
      "dist/views",
      "node_modules/@nccdigitaldev/ncc-templates/views",
      "node_modules/govuk-frontend/dist",
    ],
    {
      autoescape: true,
      express: app,
    }
  );

  app.set("view engine", nunjucksConfig);

  app.use(helmet());
  app.use("/public", express.static(path.join(__dirname, "/assets")));

  app.disable("x-powered-by");

  app.use(
    helmet({
      xPoweredBy: false,
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          scriptSrc: ["'self'", "'unsafe-inline'"],
        },
      },
    })
  );

   const redisConfig = {
     port: 6379, // To do: Redis port hardcoded. To be changed to env variable
     host: config.redisHostUrl, // Redis host
     password: config.redisPassword
   };

  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));

  if (config.env === "test") {
    app.use(
      Session({
        secret: "NCC Scaffold",
        resave: false,
        saveUninitialized: false,
        cookie: {
          httpOnly: false,
          maxAge: 1000 * 60 * 15, //15 minute cookie lifespan
        },
      })
    );
  } else {
    const client = new Redis(redisConfig);

    client.on("error", function (err) {
      logger.debug(
        "Could not establish a connection with redis. " +
          err +
          "/n" +
          JSON.stringify(redisConfig)
      );
    });

    client.on("connect", function () {
      logger.debug("Connected to redis successfully");
    });

    app.use(
      Session({
        store: new RedisStore({ client: client }),
        secret: "NCC Scaffold",
        resave: false,
        saveUninitialized: false,
        cookie: {
          httpOnly: false,
          maxAge: 1000 * 60 * 15, //15 minute cookie lifespan
        },
      })
    );
  }

  if (config.env === 'prod') {
    const csrfProtection = csrf({ cookie: true });
    app.use(cookieParser());
    app.get("*", csrfProtection);
    app.post("*", csrfProtection);
  }

  app.post("*", injectValidateFormRequest(formValidationRules));
  app.use("*", injectRequest);

  const router = setupRoutes();
  app.use(router);

  app.use(
    "*",
    (err: CustomError, req: Request, res: Response, next: NextFunction) => {
      errorHandlerMiddleware(err, req, res, next);
    }
  );

  app.use("*", navigator);

  return app;
};

export default getApp;
