import { Environment } from '@/environment';
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { AuthGuard } from '@nestjs/passport';
import { notNilEmpty } from 'qx-util';
import { FastifyRequest, FastifyReply } from 'fastify';
import { AuthService } from './auth.service';
import { CookieConstants } from '../../constants';

/**
 * jwt认证拦截器
 *
 * @author chitanda
 * @date 2021-08-16 20:08:21
 * @export
 * @class JwtAuthGuard
 * @extends {AuthGuard('jwt')}
 */
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  /**
   * 白名单
   *
   * @author chitanda
   * @date 2021-08-17 20:08:50
   * @protected
   */
  protected whiteList = new RegExp(`^${Environment.BasePath}(/v7|/app/environment)`);
  /**
   * 已有token后的白名单
   *
   * @author chitanda
   * @date 2021-08-18 00:08:49
   * @protected
   */
  protected tokenWhiteList = new RegExp(`^${Environment.BasePath}(/uaa)`);

  /**
   * 是否开启权限认证
   *
   * @author chitanda
   * @date 2021-08-22 17:08:52
   * @protected
   * @type {boolean}
   */
  protected enablePermissionValid: boolean;

  /**
   * Creates an instance of JwtAuthGuard.
   *
   * @author chitanda
   * @date 2021-08-18 22:08:46
   * @param {JwtService} jwtService
   * @param {AuthService} authService
   * @param {CachingService} cache
   */
  constructor(
    private readonly jwtService: JwtService,
    private readonly authService: AuthService,
    private readonly configService: ConfigService,
  ) {
    super();
    this.enablePermissionValid = this.configService.get<boolean>('ibiz.enablePermissionValid');
  }

  /**
   * 是否通过
   *
   * @author chitanda
   * @date 2021-08-16 20:08:37
   * @param {ExecutionContext} context
   * @return {*}  {Promise<boolean>}
   */
  async canActivate(context: ExecutionContext): Promise<boolean> {
    if (this.enablePermissionValid === false) {
      return true;
    }
    const hostArg = context.switchToHttp();
    const request: FastifyRequest = hostArg.getRequest();
    const response: FastifyReply = hostArg.getResponse();
    const url = request.url;
    // 白名单直接过
    if (this.whiteList.test(url)) {
      return true;
    }
    const oldUsername: string = request.cookies[CookieConstants.USER_NAME];
    let userName: string;
    const headers: any = request.headers;
    const { authorization } = headers;
    if (notNilEmpty(authorization)) {
      if (this.tokenWhiteList.test(url)) {
        return true;
      }
      const authToken = authorization.substring(7);
      const data = this.jwtService.decode(authToken);
      if (typeof data === 'string') {
        userName = data;
      } else {
        userName = data.sub;
      }
    }
    if (notNilEmpty(userName)) {
      if (userName !== oldUsername) {
        response.setCookie(CookieConstants.USER_NAME, userName, { path: '/' })
      }
      const query: any = request.query;
      const user = await this.authService.loginByUsername(request, response, userName);
      if (user) {
        user.srfdynainsttag = query.srfinsttag;
        user.srfdynainsttag2 = query.srfinsttag2;
      } else {
        throw new UnauthorizedException(null, '根据认证信息查找用户信息异常，请联系管理员!');
      }
      return true;
    }
    throw new UnauthorizedException();
  }

  /**
   * 异常处理
   *
   * @author chitanda
   * @date 2021-08-16 20:08:45
   * @param {*} err
   * @param {*} user
   * @param {*} info
   * @return {*}
   */
  handleRequest(err, user, _info) {
    // 可以抛出一个基于info或者err参数的异常
    if (err || !user) {
      throw err || new UnauthorizedException();
    }
    return user;
  }
}
