"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TransactionSignatureService = exports.AnnounceMode = void 0;
const symbol_sdk_1 = require("symbol-sdk");
const maxFee_resolver_1 = require("../resolvers/maxFee.resolver");
const transaction_view_1 = require("../views/transactions/details/transaction.view");
/*
 *
 * Copyright 2018-present NEM
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
var AnnounceMode;
(function (AnnounceMode) {
    AnnounceMode["standard"] = "standard";
    AnnounceMode["partial"] = "partial";
    AnnounceMode["complete"] = "complete";
})(AnnounceMode = exports.AnnounceMode || (exports.AnnounceMode = {}));
class TransactionSignatureService {
    /**
     * Constructor
     * @private
     * @param {Profile} profile
     * @param {AnnounceTransactionsOptions} options
     */
    constructor(profile, options) {
        this.profile = profile;
        this.options = options;
        this.isAggregate = false;
        this.isAggregateBonded = false;
    }
    /**
     * Gets announcement mode
     * @returns {AnnounceMode}
     */
    get announceMode() {
        if (this.isAggregateBonded || (this.multisigSigner && this.multisigSigner.info && this.multisigSigner.info.minApproval > 1)) {
            return AnnounceMode.partial;
        }
        else if (this.isAggregate || this.multisigSigner) {
            return AnnounceMode.complete;
        }
        return AnnounceMode.standard;
    }
    /**
     * Creates an instance of TransactionSignatureService.
     * @static
     * @param {Profile} profile
     * @param {AnnounceTransactionsOptions} options
     * @returns {TransactionSignatureService}
     */
    static create(profile, options) {
        return new TransactionSignatureService(profile, options);
    }
    /**
     * Signs a set of transactions.
     * @public
     * @param {TransactionSignatureOptions} args
     * @returns {Promise<SignedTransaction[]>}
     */
    async signTransactions(args) {
        const { account, transactions, multisigSigner, maxFee, isAggregate, isAggregateBonded, aggregateDeadline, transactionSigners } = args;
        this.maxFee = maxFee;
        this.transactions = transactions;
        this.multisigSigner = multisigSigner;
        this.isAggregate = isAggregate;
        this.isAggregateBonded = isAggregateBonded;
        this.signerPublicAccount = multisigSigner ? multisigSigner.publicAccount : account.publicAccount;
        this.aggregateDeadline = aggregateDeadline;
        this.transactionSigners = transactionSigners;
        if (this.announceMode === AnnounceMode.complete) {
            return this.signCompleteTransactions(account);
        }
        else if (this.announceMode === AnnounceMode.partial) {
            return this.signPartialTransactions(account);
        }
        const signedTransactions = [];
        for (const transaction of transactions) {
            const signedTransaction = await account.sign(transaction, this.profile.networkGenerationHash);
            new transaction_view_1.TransactionView(transaction, signedTransaction, this.profile).print();
            signedTransactions.push(signedTransaction);
        }
        return signedTransactions;
    }
    /**
     * Creates an aggregate bonded transaction and hash lock transaction and returns them signed.
     * @private
     * @param {Account} account - Signer account.
     * @returns {Promise<SignedTransaction[]>}
     */
    async signPartialTransactions(account) {
        const getTxSigner = (inx) => {
            if (this.transactionSigners) {
                return this.transactionSigners[inx] ? this.transactionSigners[inx] : this.signerPublicAccount;
            }
            return this.signerPublicAccount;
        };
        const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createBonded(this.aggregateDeadline ? this.aggregateDeadline : symbol_sdk_1.Deadline.create(this.profile.epochAdjustment), this.transactions.map((t, inx) => t.toAggregate(getTxSigner(inx))), this.profile.networkType, [], this.maxFee);
        const signedAggregateTransaction = await account.sign(aggregateTransaction, this.profile.networkGenerationHash);
        const hashLockTransaction = await this.createHashLockTransaction(signedAggregateTransaction);
        const signedHashLockTransaction = await account.sign(hashLockTransaction, this.profile.networkGenerationHash);
        new transaction_view_1.TransactionView(aggregateTransaction, signedAggregateTransaction, this.profile).print();
        new transaction_view_1.TransactionView(hashLockTransaction, signedHashLockTransaction, this.profile).print();
        return [signedHashLockTransaction, signedAggregateTransaction];
    }
    /**
     * Creates an aggregate complete transaction and returns it signed.
     * @private
     * @param {SigningAccount} account - Signer account.
     * @returns {SignedTransaction[]}
     */
    async signCompleteTransactions(account) {
        const getTxSigner = (inx) => {
            if (this.transactionSigners) {
                return this.transactionSigners[inx] ? this.transactionSigners[inx] : this.signerPublicAccount;
            }
            return this.signerPublicAccount;
        };
        const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(this.aggregateDeadline ? this.aggregateDeadline : symbol_sdk_1.Deadline.create(this.profile.epochAdjustment), this.transactions.map((t, inx) => t.toAggregate(getTxSigner(inx))), this.profile.networkType, [], this.maxFee);
        const signedTransaction = await account.sign(aggregateTransaction, this.profile.networkGenerationHash);
        new transaction_view_1.TransactionView(aggregateTransaction, signedTransaction, this.profile).print();
        return [signedTransaction];
    }
    async createHashLockTransaction(aggregateTx) {
        const maxFeeHashLock = await new maxFee_resolver_1.MaxFeeResolver().resolve(this.options, 'Enter the maximum fee to announce the hashlock transaction (absolute amount):', 'maxFeeHashLock');
        return symbol_sdk_1.HashLockTransaction.create(this.aggregateDeadline ? this.aggregateDeadline : symbol_sdk_1.Deadline.create(this.profile.epochAdjustment), this.profile.networkCurrency.createRelative(this.options.lockAmount), symbol_sdk_1.UInt64.fromNumericString(this.options.lockDuration), aggregateTx, this.profile.networkType, maxFeeHashLock);
    }
}
exports.TransactionSignatureService = TransactionSignatureService;
