import { DEFAULT_SCRYPT, DEFAULT_WALLET } from "../consts";
import logger from "../logging";
import { Account } from "./Account";
const log = logger("wallet");
/**
 * File to store private keys according to the NEP-2 specification.
 */
export class Wallet {
    constructor(obj = DEFAULT_WALLET) {
        var _a, _b;
        this.name = (_a = obj.name) !== null && _a !== void 0 ? _a : "myWallet";
        this.version = (_b = obj.version) !== null && _b !== void 0 ? _b : DEFAULT_WALLET.version;
        this.scrypt = Object.assign({}, DEFAULT_SCRYPT, obj.scrypt);
        this.accounts = [];
        if (obj.accounts) {
            for (const acct of obj.accounts) {
                this.addAccount(acct);
            }
        }
        log.info(`New Wallet created: ${this.name}`);
    }
    get [Symbol.toStringTag]() {
        return "Wallet";
    }
    /**
     * Returns the default Account according to the following rules:
     * 1. First Account where isDefault is true.
     * 2. First Account with a decrypted private key.
     * 3. First Account with an encrypted private key.
     * 4. First Account in the array.
     * Throws error if no accounts available.
     */
    get defaultAccount() {
        if (this.accounts.length === 0) {
            throw new Error("No accounts available in this Wallet!");
        }
        for (const acct of this.accounts) {
            if (acct.isDefault) {
                return acct;
            }
        }
        for (const acct of this.accounts) {
            if (acct.tryGet("privateKey") || acct.tryGet("WIF")) {
                return acct;
            }
        }
        for (const acct of this.accounts) {
            if (acct.encrypted) {
                return acct;
            }
        }
        return this.accounts[0];
    }
    /**
     * Adds an account.
     * @param acct - Account or WalletAccount object.
     * @returns index position of Account in array.
     */
    addAccount(acct) {
        const index = this.accounts.length;
        if (!(acct instanceof Account)) {
            acct = new Account(acct);
        }
        if (index === 0) {
            acct.isDefault = true;
        }
        this.accounts.push(acct);
        try {
            const address = acct.address;
            log.info(`Added Account: ${address} to Wallet ${this.name}`);
        }
        catch (err) {
            log.warn(`Encrypted account added to Wallet ${this.name}. You will not be able to export this wallet without first decrypting this account`);
        }
        return index;
    }
    /**
     * Attempts to decrypt Account at index in array.
     * @param index - index of Account in array.
     * @param keyphrase - keyphrase
     * @returns Promise of decryption success/failure.
     */
    async decrypt(index, keyphrase) {
        if (index < 0) {
            throw new Error(`Index cannot be negative! index: ${index}`);
        }
        if (index >= this.accounts.length) {
            throw new Error(`Index cannot larger than Accounts array! index: ${index}`);
        }
        await this.accounts[index].decrypt(keyphrase, this.scrypt);
        return true;
    }
    /**
     * Attempts to decrypt all accounts with keyphrase.
     * @returns Promise of accounts decryption success/failure .
     */
    decryptAll(keyphrase) {
        return Promise.all(this.accounts.map((acct, i) => this.decrypt(i, keyphrase)));
    }
    /**
     * Attempts to encrypt Account at index in array.
     * @param index - index of Account in array.
     * @param keyphrase - keyphrase
     * @returns Promise of encryption success/failure.
     */
    async encrypt(index, keyphrase) {
        if (index < 0) {
            throw new Error("Index cannot be negative!");
        }
        if (index >= this.accounts.length) {
            throw new Error("Index cannot larger than Accounts array!");
        }
        await this.accounts[index].encrypt(keyphrase, this.scrypt);
        return true;
    }
    /**
     * Attempts to encrypt all accounts with keyphrase.
     * @param keyphrase - keyphrase
     * @returns Promise of accounts encryption success/failure.
     */
    encryptAll(keyphrase) {
        return Promise.all(this.accounts.map((acct, i) => this.encrypt(i, keyphrase)));
    }
    /**
     * Export this class as a JS object.
     */
    export() {
        return {
            name: this.name,
            version: this.version,
            scrypt: this.scrypt,
            accounts: this.accounts.map((acct) => acct.export()),
        };
    }
    /**
     * Set Account at index in array to be default account.
     * @param index - index of the Account in accounts array.
     */
    setDefault(index) {
        for (let i = 0; i < this.accounts.length; i++) {
            this.accounts[i].isDefault = i === index;
        }
        log.info(`Set Account: ${this.accounts[index]} as default for Wallet ${this.name}`);
        return this;
    }
}
export default Wallet;
//# sourceMappingURL=Wallet.js.map