import { doubleCsrf } from 'csrf-csrf';
import { Application } from 'express';
import { Logger, LoggerService } from './logger.js';
import { Common, CommonService } from './common.js';

class CSRF {

  public logger: LoggerService = Logger;
  public common: CommonService = Common;

  // Signed double-submit-cookie protection (replaces the deprecated csurf).
  // The signed token lives in the httpOnly '_csrf' cookie; the client echoes
  // the same token (read from the XSRF-TOKEN cookie set in app.ts) in a
  // header. The cookie is not secure-only because RTL commonly serves plain
  // HTTP (matching the session cookie); token sources match what csurf
  // accepted. The error code EBADCSRFTOKEN is handled in app.ts.
  private doubleCsrfUtilities = doubleCsrf({
    getSecret: () => this.common.secret_key,
    getSessionIdentifier: (req: any) => (req.session ? req.session.id : ''),
    cookieName: '_csrf',
    cookieOptions: { sameSite: 'strict', path: '/', secure: false, httpOnly: true },
    getCsrfTokenFromRequest: (req: any) => (req.body && req.body._csrf) || (req.query && req.query._csrf) ||
      req.headers['csrf-token'] || req.headers['xsrf-token'] ||
      req.headers['x-csrf-token'] || req.headers['x-xsrf-token']
  });

  public csrfProtection = this.doubleCsrfUtilities.doubleCsrfProtection;

  // Force-mints a fresh token for the current session, discarding any token
  // cookie bound to a previous session or boot secret (used by the
  // EBADCSRFTOKEN error path in app.ts so a client retry succeeds).
  public reMintToken = (req, res) => this.doubleCsrfUtilities.generateCsrfToken(req, res, { overwrite: true });

  public mount(app: Application): Application {
    this.logger.log({ selectedNode: this.common.selectedNode, level: 'INFO', fileName: 'CSRF', msg: 'Setting up CSRF..' });
    if (process.env.NODE_ENV !== 'development') {
      app.use((req, res, next) => this.csrfProtection(req, res, next));
    }
    this.logger.log({ selectedNode: this.common.selectedNode, level: 'INFO', fileName: 'CSRF', msg: 'CSRF Set' });
    return app;
  };

}

export default new CSRF;
