import { KeyStore } from 'cic-client-meta';
// TODO should we put this on the mutable key store object
import * as openpgp from 'openpgp';
const keyring = new openpgp.Keyring();

interface MutableKeyStore extends KeyStore {
  loadKeyring(): void;
  importKeyPair(publicKey: any, privateKey: any): Promise<void>;
  importPublicKey(publicKey: any): void;
  importPrivateKey(privateKey: any): Promise<void>;
  getPublicKeys(): Array<any>;
  getTrustedKeys(): Array<any>;
  getTrustedActiveKeys(): Array<any>;
  getEncryptKeys(): Array<any>;
  getPrivateKeys(): Array<any>;
  getPrivateKey(): any;
  isValidKey(key: any): Promise<boolean>;
  isEncryptedPrivateKey(privateKey: any): Promise<boolean>;
  getFingerprint(): string;
  getKeyId(key: any): string;
  getPrivateKeyId(): string;
  getKeysForId(keyId: string): Array<any>;
  getPublicKeyForId(keyId: string): any;
  getPrivateKeyForId(keyId: string): any;
  getPublicKeyForSubkeyId(subkeyId: string): any;
  getPublicKeysForAddress(address: string): Array<any>;
  removeKeysForId(keyId: string): Array<any>;
  removePublicKeyForId(keyId: string): any;
  removePublicKey(publicKey: any): any;
  clearKeysInKeyring(): void;
  sign(plainText: string): Promise<any>;
}

class MutablePgpKeyStore implements MutableKeyStore {
  async loadKeyring(): Promise<void> {
    await keyring.load();
    await keyring.store();
  }

  async importKeyPair(publicKey: any, privateKey: any): Promise<void> {
    await keyring.publicKeys.importKey(publicKey);
    await keyring.privateKeys.importKey(privateKey);
  }

  importPublicKey(publicKey: any): void {
    keyring.publicKeys.importKey(publicKey);
  }

  async importPrivateKey(privateKey: any): Promise<void> {
    await keyring.privateKeys.importKey(privateKey);
  }

  getPublicKeys(): Array<any> {
    return keyring.publicKeys.keys;
  }

  getTrustedKeys(): Array<any> {
    return keyring.publicKeys.keys;
  }

  getTrustedActiveKeys(): Array<any> {
    return keyring.publicKeys.keys;
  }

  getEncryptKeys(): Array<any> {
    return [];
  }

  getPrivateKeys(): Array<any> {
    return keyring.privateKeys.keys;
  }

  getPrivateKey(): any {
    return keyring.privateKeys && keyring.privateKeys.keys[0];
  }

  async isValidKey(key): Promise<boolean> {
    // There is supposed to be an openpgp.readKey() method but I can't find it?
    const testKey = await openpgp.key.readArmored(key);
    return !testKey.err;
  }

  async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
    const imported = await openpgp.key.readArmored(privateKey);
    for (const key of imported.keys) {
      if (key.isDecrypted()) {
        return false;
      }
    }
    return true;
  }

  getFingerprint(): string {
    // TODO Handle multiple keys
    return (
      keyring.privateKeys &&
      keyring.privateKeys.keys[0] &&
      keyring.privateKeys.keys[0].keyPacket &&
      keyring.privateKeys.keys[0].keyPacket.fingerprint
    );
  }

  getKeyId(key: any): string {
    return key.getKeyId().toHex();
  }

  getPrivateKeyId(): string {
    // TODO is there a library that comes with angular for doing this?
    return (
      keyring.privateKeys &&
      keyring.privateKeys.keys[0] &&
      keyring.privateKeys.keys[0].getKeyId().toHex()
    );
  }

  getKeysForId(keyId: string): Array<any> {
    return keyring.getKeysForId(keyId);
  }

  getPublicKeyForId(keyId): any {
    return keyring.publicKeys.getForId(keyId);
  }

  getPrivateKeyForId(keyId): any {
    return keyring.privateKeys.getForId(keyId);
  }

  getPublicKeyForSubkeyId(subkeyId): any {
    return keyring.publicKeys.getForId(subkeyId, true);
  }

  getPublicKeysForAddress(address): Array<any> {
    return keyring.publicKeys.getForAddress(address);
  }

  removeKeysForId(keyId): Array<any> {
    return keyring.removeKeysForId(keyId);
  }

  removePublicKeyForId(keyId): any {
    return keyring.publicKeys.removeForId(keyId);
  }

  removePublicKey(publicKey: any): any {
    const keyId = publicKey.getKeyId().toHex();
    return keyring.publicKeys.removeForId(keyId);
  }

  clearKeysInKeyring(): void {
    keyring.clear();
  }

  async sign(plainText): Promise<any> {
    const privateKey = this.getPrivateKey();
    if (!privateKey.isDecrypted()) {
      const password = window.prompt('password');
      await privateKey.decrypt(password);
    }
    const opts = {
      message: openpgp.message.fromText(plainText),
      privateKeys: [privateKey],
      detached: true,
    };
    const signatureObject = await openpgp.sign(opts);
    return signatureObject.signature;
  }
}

export { MutablePgpKeyStore, MutableKeyStore };
