import {
  Injectable,
  InternalServerErrorException,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService as NestJWTService } from '@nestjs/jwt';
import { Payload } from './interfaces/Payload';
import * as Joi from 'joi';

@Injectable()
export class JWTService {
  constructor(private nestJWTService: NestJWTService) {}

  async generateToken(payload: Payload): Promise<string> {
    const schema = Joi.object({
      id: Joi.number().integer().min(1).strict().required(),
      googleId: Joi.string().max(256).allow(null).optional(),
    });

    try {
      await schema.validateAsync(payload);
    } catch {
      throw new InternalServerErrorException();
    }

    return await this.nestJWTService.signAsync(payload, {
      expiresIn: '1d',
    });
  }

  async verifyToken(token: string): Promise<Payload> {
    if (!token) throw new UnauthorizedException();

    try {
      const { id, googleId } = await this.nestJWTService.verifyAsync(token);

      const payload: Payload = { id, googleId };

      const schema = Joi.object({
        id: Joi.number().integer().min(1).strict().required(),
        googleId: Joi.string().max(256).allow(null).optional(),
      });

      await schema.validateAsync(payload);

      return payload;
    } catch {
      throw new UnauthorizedException();
    }
  }

  async retrievePayload(token: string): Promise<Payload> {
    try {
      const { id, googleId } = await this.nestJWTService.verifyAsync(token);

      const payload: Payload = { id, googleId };

      const schema = Joi.object({
        id: Joi.number().integer().min(1).strict().required(),
        googleId: Joi.string().max(256).allow(null).optional(),
      });

      await schema.validateAsync(payload);

      return payload;
    } catch {
      return null;
    }
  }
}
