import { Injectable } from '@nestjs/common';
import { CsrfTokenCreator, DoubleCsrfConfigOptions, doubleCsrf, doubleCsrfProtection } from 'csrf-csrf';
import { Request, Response, NextFunction } from 'express';
import { cookieOptions } from '../common/constants/cookieOptions.constant';

@Injectable()
export class CsrfService {
  public generateToken: CsrfTokenCreator;
  public doubleCsrfProtection: doubleCsrfProtection;
  // public generateToken: CsrfTokenGenerator;
  // public csrfSynchronisedProtection: CsrfSynchronisedProtection;
  public csrfErrorHandler: any;

  constructor() {}

  // https://github.com/Psifi-Solutions/csrf-csrf
  initDoubleCsrf(DOMAIN: string, CSRF_SECRET: string) {
    const {
      invalidCsrfTokenError, // This is just for convenience if you plan on making your own middleware.
      generateToken, // Use this in your routes to provide a CSRF hash cookie and token.
      // validateRequest, // Also a convenience if you plan on making your own middleware.
      doubleCsrfProtection, // This is the default CSRF protection middleware.
    } = doubleCsrf(<DoubleCsrfConfigOptions>{
      getSecret: (req: Request) => req.secret,
      secret: CSRF_SECRET, // A function that optionally takes the request and returns a secret
      cookieName: `__${DOMAIN}-x-csrf-token`, // The name of the cookie to be used, recommend using Host prefix.
      cookieOptions: cookieOptions(),
      size: 64, // The size of the generated tokens in bits
      ignoredMethods: ['GET', 'HEAD', 'OPTIONS'] // A list of request methods that will not be protected.
    });
    this.generateToken = generateToken;
    this.doubleCsrfProtection = doubleCsrfProtection;
    // Error handling, validation error interception
    this.csrfErrorHandler = (error: Error, req: Request, res: Response, next: NextFunction) => {
      // console.log(error, Object.keys(req))
      // console.log(req.cookies)
      // console.log(req.signedCookies)
      // console.log(req.csrfToken)
      if (error == invalidCsrfTokenError) {
        const status = 401;
        const statusMessage = 'Unauthorized';
        res.statusMessage = statusMessage;
        res.status(status).json({ status, statusMessage, message: 'INVALID_CSRF' });
        return res;
      } else {
        next();
      }
    }
  }
}