/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import IKeyStore, { KeyStoreListItem } from './IKeyStore';
import IKeyContainer, { CryptographicKey } from '../keys/IKeyContainer';
import { KeyType } from '../keys/KeyTypeFactory';
import { PrivateKey } from '../..';
const clone = require('clone');

/**
 * Class defining methods and properties for a light KeyStore
 */
export default class KeyStoreInMemory implements IKeyStore {
  private store: Map<string, IKeyContainer> = new Map<string, IKeyContainer>();

  /**
   * Returns the key container associated with the specified
   * key identifier.
   * @param keyReference for which to return the key.
   * @param [publicKeyOnly] True if only the public key is needed.
   */
  get (keyReference: string, publicKeyOnly: boolean = true): Promise<IKeyContainer> {
    return new Promise((resolve, reject) => {
      if (this.store.has(keyReference)) {
        const key = (<IKeyContainer>this.store.get(keyReference));
        if (key.kty === KeyType.Oct) {
          if (publicKeyOnly) {
            throw new Error('A secret does not has a public key');
          }
          return resolve(key);
        }

        if (publicKeyOnly) {
          switch (key.kty.toLowerCase()) {
            case 'ec':
            case 'okp':
            case 'rsa':
              return resolve(this.publicKeysOnly(key));
            default:
              throw new Error(`A secret does not has a public key`);
          }
        } else {
          resolve(key);
        }

      } else {
        reject(`${keyReference} not found`);
      }
    });
  }

  private publicKeysOnly(container: IKeyContainer) {
    const publicKeyContainer = clone(container);
    for (let inx = 0; inx < publicKeyContainer.keys.length; inx++) {
      if (publicKeyContainer.keys[inx].getPublicKey) {
        publicKeyContainer.keys[inx] = (<PrivateKey>publicKeyContainer.keys[inx]).getPublicKey();
      }
    }
    return publicKeyContainer;
  }

 /**
  * Lists all keys with their corresponding key ids
  */
  list (): Promise<{ [name: string]: KeyStoreListItem }> {
    const dictionary: { [name: string]: KeyStoreListItem } = {};
    for (let [key, container] of this.store) {
      if ((<any>container)) {
        const keyListInContainer: KeyStoreListItem = {kty: container.kty, kids: []};
        dictionary[key] = keyListInContainer;
        for (let keyInContainer of container.keys) {
          keyListInContainer.kids.push(<string>keyInContainer.kid);
        }
      }
    }
    return new Promise((resolve) => {
      resolve(dictionary);
    });
  }

  /**
   * Saves the specified key to the key store using
   * the key identifier.
   * @param keyIdentifier for the key being saved.
   * @param key being saved to the key store.
   */
  save (keyIdentifier: string, key: IKeyContainer): Promise<void> {
    console.log(this.store.toString() + keyIdentifier + key.toString());
    this.store.set(keyIdentifier, key);
    return new Promise((resolve) => {
      resolve();
    });
  }
}
