import { verifyAccessJWT } from '../../src/utils/jwt';
import jwt from 'jsonwebtoken';
import { InvalidTokenException, ServiceUnavailableException, TokenExpiredException } from '../../src/exceptions';
import { DirectusTokenPayload } from '../../src/types';

const payload: DirectusTokenPayload = { role: null, app_access: false, admin_access: false };
const secret = 'test-secret';
const options = { issuer: 'directus' };

test('Returns the payload of a correctly signed token', () => {
	const token = jwt.sign(payload, secret, options);
	const result = verifyAccessJWT(token, secret);
	expect(result).toEqual(payload);
});

test('Throws TokenExpiredException when token used has expired', () => {
	const token = jwt.sign({ ...payload, exp: new Date().getTime() / 1000 - 500 }, secret, options);
	expect(() => verifyAccessJWT(token, secret)).toThrow(TokenExpiredException);
});

const InvalidTokenCases = {
	'wrong issuer': jwt.sign(payload, secret, { issuer: 'wrong' }),
	'wrong secret': jwt.sign(payload, 'wrong-secret', options),
	'string payload': jwt.sign('illegal payload', secret),
	'missing properties in token payload': jwt.sign({ role: null }, secret, options),
};

Object.entries(InvalidTokenCases).forEach(([title, token]) =>
	test(`Throws InvalidTokenError - ${title}`, () => {
		expect(() => verifyAccessJWT(token, secret)).toThrow(InvalidTokenException);
	})
);

test(`Throws ServiceUnavailableException for unexpected error from jsonwebtoken`, () => {
	jest.spyOn(jwt, 'verify').mockImplementation(() => {
		throw new Error();
	});

	const token = jwt.sign(payload, secret, options);
	expect(() => verifyAccessJWT(token, secret)).toThrow(ServiceUnavailableException);
});
