// TODO makeMockBridge need to be exploded into families (bridge/mock) with utility code shared.
import { genOperation } from "@ledgerhq/coin-framework/mocks/account";
import { BigNumber } from "bignumber.js";
import Prando from "prando";
import { Observable, of } from "rxjs";
import { getEnv } from "@ledgerhq/live-env";
import perFamilyMock from "../generated/mock";
import { genAccount } from "../mock/account";
import { getOperationAmountNumber } from "../operation";
import { delay } from "../promise";
const MOCK_DATA_SEED = getEnv("MOCK") || "MOCK";
const broadcasted = {};
const syncTimeouts = {};
export const sync = initialAccount => new Observable(o => {
    const accountId = initialAccount.id;
    const sync = () => {
        const ops = broadcasted[accountId] || [];
        broadcasted[accountId] = [];
        o.next(acc => {
            const balance = ops.reduce((sum, op) => sum.plus(getOperationAmountNumber(op)), acc.balance);
            const nextAcc = {
                ...acc,
                blockHeight: acc.blockHeight + 1000,
                lastSyncDate: new Date(),
                operations: ops.concat(acc.operations.slice(0)),
                pendingOperations: [],
                balance,
                spendableBalance: balance,
            };
            const perFamilyOperation = perFamilyMock[acc.currency.id];
            const postSyncAccount = perFamilyOperation && perFamilyOperation.postSyncAccount;
            if (postSyncAccount)
                return postSyncAccount(nextAcc);
            return nextAcc;
        });
        o.complete();
    };
    syncTimeouts[accountId] = setTimeout(sync, 500);
    return () => {
        clearTimeout(syncTimeouts[accountId]);
        syncTimeouts[accountId] = null;
    };
});
export const broadcast = ({ signedOperation }) => Promise.resolve(signedOperation.operation);
export const signOperation = ({ account, transaction }) => new Observable(o => {
    let cancelled = false;
    async function main() {
        await delay(1000);
        if (cancelled)
            return;
        for (let i = 0; i <= 1; i += 0.1) {
            o.next({
                type: "device-streaming",
                progress: i,
                index: i,
                total: 10,
            });
            await delay(300);
        }
        o.next({
            type: "device-signature-requested",
        });
        await delay(2000);
        if (cancelled)
            return;
        o.next({
            type: "device-signature-granted",
        });
        const rng = new Prando("");
        const op = genOperation(account, account, account.operations, rng);
        op.type = "OUT";
        op.value = transaction.amount;
        op.blockHash = null;
        op.blockHeight = null;
        op.senders = [account.freshAddress];
        op.recipients = [transaction.recipient];
        op.blockHeight = account.blockHeight;
        op.date = new Date();
        await delay(1000);
        if (cancelled)
            return;
        broadcasted[account.id] = (broadcasted[account.id] || []).concat(op);
        o.next({
            type: "signed",
            signedOperation: {
                operation: { ...op },
                signature: "",
            },
        });
    }
    main().then(() => o.complete(), e => o.error(e));
    return () => {
        cancelled = true;
    };
});
export { isInvalidRecipient } from "./validateAddress";
const subtractOneYear = date => new Date(new Date(date).setFullYear(new Date(date).getFullYear() - 1));
export const scanAccounts = ({ currency }) => new Observable(o => {
    let unsubscribed = false;
    async function job() {
        // TODO offer a way to mock a failure
        const nbAccountToGen = 3;
        for (let i = 0; i < nbAccountToGen && !unsubscribed; i++) {
            const isLast = i === 2;
            await delay(500);
            const account = genAccount(`${MOCK_DATA_SEED}_${currency.id}_${i}`, {
                operationsSize: isLast ? 0 : 100,
                currency,
                subAccountsCount: isLast ? 0 : undefined,
                bandwidth: !isLast,
            });
            account.index = i;
            account.operations = isLast
                ? []
                : account.operations.map(operation => ({
                    ...operation,
                    date: subtractOneYear(operation.date),
                }));
            account.used = isLast ? false : account.used;
            if (isLast) {
                account.spendableBalance = account.balance = new BigNumber(0);
            }
            const perFamilyOperation = perFamilyMock[currency.id];
            const postScanAccount = perFamilyOperation && perFamilyOperation.postScanAccount;
            if (postScanAccount)
                postScanAccount(account, {
                    isEmpty: isLast,
                });
            if (!unsubscribed)
                o.next({
                    type: "discovered",
                    account,
                });
        }
        if (!unsubscribed)
            o.complete();
    }
    job();
    return () => {
        unsubscribed = true;
    };
});
export const makeAccountBridgeReceive = () => account => of({
    address: account.freshAddress,
    path: account.freshAddressPath,
    publicKey: "mockPublickKey", // We could probably keep the publicKey in `account.freshPublicKey`
});
export const signRawOperation = ({ account }) => new Observable(o => {
    let cancelled = false;
    async function main() {
        await delay(1000);
        if (cancelled)
            return;
        for (let i = 0; i <= 1; i += 0.1) {
            o.next({
                type: "device-streaming",
                progress: i,
                index: i,
                total: 10,
            });
            await delay(300);
        }
        o.next({
            type: "device-signature-requested",
        });
        await delay(2000);
        if (cancelled)
            return;
        o.next({
            type: "device-signature-granted",
        });
        const rng = new Prando("");
        const op = genOperation(account, account, account.operations, rng);
        op.type = "OUT";
        op.value = new BigNumber(0);
        op.blockHash = null;
        op.blockHeight = null;
        op.senders = [account.freshAddress];
        op.recipients = [];
        op.blockHeight = account.blockHeight;
        op.date = new Date();
        await delay(1000);
        if (cancelled)
            return;
        broadcasted[account.id] = (broadcasted[account.id] || []).concat(op);
        o.next({
            type: "signed",
            signedOperation: {
                operation: { ...op },
                signature: "",
            },
        });
    }
    main().then(() => o.complete(), e => o.error(e));
    return () => {
        cancelled = true;
    };
});
//# sourceMappingURL=mockHelpers.js.map