import { jws } from 'jsrsasign';
import NodeRSA from 'node-rsa';
import { HTTP } from 'meteor/http';
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { Match, check } from 'meteor/check';

const isValidAppleJWT = (identityToken, header) => {
	const applePublicKeys = HTTP.get('https://appleid.apple.com/auth/keys').data.keys;
	const { kid } = header;

	const key = applePublicKeys.find((k) => k.kid === kid);

	const pubKey = new NodeRSA();
	pubKey.importKey(
		{ n: Buffer.from(key.n, 'base64'), e: Buffer.from(key.e, 'base64') },
		'components-public',
	);
	const userKey = pubKey.exportKey(['public']);

	try {
		return jws.JWS.verify(identityToken, userKey, {
			typ: 'JWT',
			alg: 'RS256',
		});
	} catch {
		return false;
	}
};

export const handleIdentityToken = ({ identityToken, fullName, email }) => {
	check(identityToken, String);
	check(fullName, Match.Maybe(Object));
	check(email, Match.Maybe(String));

	const decodedToken = jws.JWS.parse(identityToken);

	if (!isValidAppleJWT(identityToken, decodedToken.headerObj)) {
		return {
			type: 'apple',
			error: new Meteor.Error(Accounts.LoginCancelledError.numericError, 'identityToken is a invalid JWT'),
		};
	}

	const profile = {};

	const { givenName, familyName } = fullName;
	if (givenName && familyName) {
		profile.name = `${ givenName } ${ familyName }`;
	}

	const { iss, iat, exp } = decodedToken.payloadObj;

	if (!iss) {
		return {
			type: 'apple',
			error: new Meteor.Error(Accounts.LoginCancelledError.numericError, 'Insufficient data in auth response token'),
		};
	}

	// Collect basic auth provider details
	const serviceData = {
		id: iss,
		did: iss.split(':').pop(),
		issuedAt: new Date(iat * 1000),
		expiresAt: new Date(exp * 1000),
	};

	if (email) {
		serviceData.email = email;
	}

	return {
		serviceData,
		options: { profile },
	};
};
