/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import Identifier from '../Identifier';
import UserAgentError from '../UserAgentError';
import JwsToken from '../crypto/protocols/jose/jws/JwsToken';
import IdentifierDocument from '../IdentifierDocument';

export default class VerifyHelper {

  /**
   * Verify that Jwstoken was signed by the entity that 
   * owns the Identifier Document referenced by the senderId.
   * @param sender the Identifier of the entity whose signature we are verifying.
   * @param token the token that is being verified. 
   */
  public static async verify(sender: Identifier, token: JwsToken) {
    const senderDocument = await sender.getDocument();
    const matchingPublicKeys = this.findMatchingPublicKeys(token, senderDocument);
    return token.verify(matchingPublicKeys);
  }

  /**
   * Find Public Keys in an Identifier Document that
   * match the ones specified in header/protected header of a signed token.
   * @param token JWSToken whose signature needs to be matched
   * @param document Identifer Document containing public keys
   */
  private static findMatchingPublicKeys(token: JwsToken, document: IdentifierDocument) {
    if (token.signatures.length < 0) {
      throw new UserAgentError('No signature included');
    }
    let keyMatches: RegExpMatchArray | null = null;
    const keyIdRegex = /([^#]*)#?(.+$)/;
    if (token.signatures[0].protected && (token.signatures[0].protected).has('kid')) {
      const keyIdentifier: string = (token.signatures[0].protected).get('kid');
      keyMatches = keyIdentifier.match(keyIdRegex);
    } else if (token.signatures[0].header && (token.signatures[0].header).has('kid')) {
      const keyIdentifier: string = (token.signatures[0].header).get('kid');
      keyMatches = keyIdentifier.match(keyIdRegex);
    }
    if (keyMatches ===  null) {
      throw new UserAgentError('Cannot locate keyID');
    }
    if (keyMatches[1].length > 0 && keyMatches[1] !== document.id) {
      throw new UserAgentError('Issuer signer does not match issuer');
    }
    const keyId = keyMatches[2];

    const publicKeysFromDocument = document.getPublicKeysFromDocument();
    return publicKeysFromDocument.filter((publicKey) => {
      return publicKey.kid && publicKey.kid.endsWith(keyId);
    });
  }
}
