"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatOperation = exports.formatAccount = exports.accountFormatters = void 0;
const index_1 = require("@ledgerhq/coin-framework/account/index");
const derivation_1 = require("@ledgerhq/coin-framework/derivation");
const operation_1 = require("@ledgerhq/coin-framework/operation");
const accountName_1 = require("@ledgerhq/live-wallet/accountName");
const bignumber_js_1 = require("bignumber.js");
const invariant_1 = __importDefault(require("invariant"));
const currencies_1 = require("../currencies");
const serialization_1 = require("./serialization");
const bridge_1 = require("../bridge");
const isSignificantAccount = acc => acc.balance.gt(10 ** ((0, index_1.getAccountCurrency)(acc).units[0].magnitude - 6));
const formatOp = (unitByAccountId, familySpecific) => {
    const format = (op, level = 0) => {
        const unit = unitByAccountId(op.accountId);
        const amountBN = (0, operation_1.getOperationAmountNumber)(op);
        const amount = unit
            ? (0, currencies_1.formatCurrencyUnit)(unit, amountBN, {
                showCode: true,
                alwaysShowSign: true,
                disableRounding: true,
            })
            : "? " + amountBN.toString();
        const spaces = Array((level + 1) * 2)
            .fill(" ")
            .join("");
        let extra = level > 0 ? "" : `${op.hash} ${op.date.toISOString().split(":").slice(0, 2).join(":")}`;
        extra += familySpecific(op, unit);
        const head = `${(spaces + amount).padEnd(20)} ${((op.hasFailed ? "❌" : "") +
            op.type +
            " ").padEnd(11)}${extra}`;
        const sub = (op.subOperations || [])
            .concat(op.internalOperations || [])
            .map(subop => format(subop, level + 1))
            .join("");
        return `\n${head}${sub}`;
    };
    return (op) => format(op, 0);
};
function maybeDisplaySumOfOpsIssue(ops, balance, unit) {
    const sumOfOps = ops.reduce((sum, op) => sum.plus((0, operation_1.getOperationAmountNumber)(op)), new bignumber_js_1.BigNumber(0));
    if (sumOfOps.eq(balance))
        return "";
    return (" (! sum of ops " +
        (0, currencies_1.formatCurrencyUnit)(unit, sumOfOps, {
            showCode: true,
            disableRounding: true,
        }) +
        ")");
}
const cliFormat = (account, level) => {
    const { id, name, freshAddress, freshAddressPath, derivationMode, index, operations } = account;
    const tag = (0, derivation_1.getTagDerivationMode)(account.currency, derivationMode);
    const balance = (0, currencies_1.formatCurrencyUnit)((0, index_1.getAccountCurrency)(account).units[0], account.balance, {
        showCode: true,
    });
    const opsCount = `${operations.length}ops`;
    const freshInfo = `${freshAddress} on ${freshAddressPath}`;
    const derivationInfo = `${derivationMode}#${index}`;
    let str = `${name}${tag ? " [" + tag + "]" : ""}: ${balance} (${opsCount}) (${freshInfo}) ${derivationInfo} ${id || ""}`;
    if (level === "head")
        return str;
    str += maybeDisplaySumOfOpsIssue(operations, account.balance, (0, index_1.getAccountCurrency)(account).units[0]);
    const formatAccountSpecifics = (0, bridge_1.getAccountBridge)(account).formatAccountSpecifics;
    if (formatAccountSpecifics) {
        str += formatAccountSpecifics(account);
        str += "\n";
    }
    const subAccounts = account.subAccounts || [];
    str += subAccounts
        .map(ta => "  " +
        ta.type +
        " " +
        (0, accountName_1.getDefaultAccountName)(ta) +
        ": " +
        (0, currencies_1.formatCurrencyUnit)((0, index_1.getAccountCurrency)(ta).units[0], ta.balance, {
            showCode: true,
            disableRounding: true,
        }) +
        " (" +
        ta.operations.length +
        " ops)" +
        maybeDisplaySumOfOpsIssue(ta.operations, ta.balance, (0, index_1.getAccountCurrency)(ta).units[0]))
        .join("\n");
    if (level === "basic")
        return str;
    str += "\nOPERATIONS (" + operations.length + ")";
    str += operations
        .map(formatOp(id => {
        if (account.id === id)
            return (0, index_1.getAccountCurrency)(account).units[0];
        const ta = subAccounts.find(a => a.id === id);
        if (ta)
            return (0, index_1.getAccountCurrency)(ta).units[0];
        console.error("unexpected missing token account " + id);
    }, (operation, unit) => {
        return (0, bridge_1.getAccountBridge)(account).formatOperationSpecifics?.(operation, unit) ?? "";
    }))
        .join("");
    return str;
};
const stats = account => {
    const { subAccounts, operations } = account;
    const sumOfAllOpsNumber = operations.reduce((sum, op) => sum.plus((0, operation_1.getOperationAmountNumberWithInternals)(op)), new bignumber_js_1.BigNumber(0));
    const sumOfAllOps = (0, currencies_1.formatCurrencyUnit)((0, index_1.getAccountCurrency)(account).units[0], sumOfAllOpsNumber, {
        showCode: true,
    });
    const balance = (0, currencies_1.formatCurrencyUnit)((0, index_1.getAccountCurrency)(account).units[0], account.balance, {
        showCode: true,
    });
    return {
        balance,
        sumOfAllOps,
        opsCount: operations.length,
        subAccountsCount: (subAccounts || []).length,
    };
};
// this is developped for debug purpose in order to compare with balance APIs
const operationBalanceHistoryBackwards = account => {
    let acc = account.balance;
    return JSON.stringify(account.operations
        .map(op => {
        const { blockHeight } = op;
        const date = op.date.toISOString();
        const balance = acc.toNumber();
        acc = acc.minus((0, operation_1.getOperationAmountNumberWithInternals)(op));
        return { blockHeight, date, balance };
    })
        .reverse());
};
const operationBalanceHistory = account => {
    let acc = new bignumber_js_1.BigNumber(0);
    return JSON.stringify(account.operations
        .slice(0)
        .reverse()
        .map(op => {
        acc = acc.plus((0, operation_1.getOperationAmountNumberWithInternals)(op));
        const { blockHeight } = op;
        const date = op.date.toISOString();
        const balance = acc.toNumber();
        return { blockHeight, date, balance };
    }));
};
exports.accountFormatters = {
    operationBalanceHistoryBackwards,
    operationBalanceHistory,
    json: account => JSON.stringify((0, serialization_1.toAccountRaw)(account)),
    head: account => cliFormat(account, "head"),
    default: account => cliFormat(account),
    basic: account => cliFormat(account, "basic"),
    full: account => cliFormat(account, "full"),
    stats: account => stats(account),
    significantTokenTickers: account => (account.subAccounts || [])
        .filter(isSignificantAccount)
        .map(ta => (0, index_1.getAccountCurrency)(ta).ticker)
        .join("\n"),
};
function formatAccount(account, format = "full") {
    const f = exports.accountFormatters[format];
    (0, invariant_1.default)(f, "missing account formatter=" + format);
    return f(account);
}
exports.formatAccount = formatAccount;
function formatOperation(account) {
    const unitByAccountId = (id) => {
        if (!account)
            return;
        if (account.id === id)
            return (0, index_1.getAccountCurrency)(account).units[0];
        const ta = (account.subAccounts || []).find(a => a.id === id);
        if (ta)
            return (0, index_1.getAccountCurrency)(ta).units[0];
    };
    const familyExtra = (operation, unit) => {
        if (!account)
            return "";
        return (0, bridge_1.getAccountBridge)(account).formatOperationSpecifics?.(operation, unit) ?? "";
    };
    return formatOp(unitByAccountId, familyExtra);
}
exports.formatOperation = formatOperation;
//# sourceMappingURL=formatters.js.map