#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mongodb_1 = require("mongodb");
const wallet_1 = require("../build/src/models/wallet");
const walletAddress_1 = require("../build/src/models/walletAddress");
const storage_1 = require("../build/src/services/storage");
const utils_1 = require("../build/src/utils");
function usage(errMsg) {
    console.log('USAGE: ./migrateTestnetWallets.js [options]');
    console.log('OPTIONS:');
    console.log('  --chain <value>         REQUIRED - e.g. BTC, BCH, DOGE, LTC...');
    console.log('  --oldNetwork <value>    REQUIRED - e.g. testnet3');
    console.log('  --newNetwork <value>    REQUIRED - e.g. testnet4');
    console.log('  --batchSize <value>     Number of documents to update at a time. Default: 10000');
    console.log('  --deDup                 Delete duplicate walletAddresses (dups can happen if an updated wallet is queried before addresses are updated)');
    console.log('  --doit                  Save the migration to the db. Make sure you stop sync services before running this script');
    if (errMsg) {
        console.log('\nERROR: ' + errMsg);
    }
    process.exit();
}
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
    usage();
}
const chainIdx = args.indexOf('--chain');
const oldNetworkIdx = args.indexOf('--oldNetwork');
const newNetworkIdx = args.indexOf('--newNetwork');
const chain = args[chainIdx + 1]?.toUpperCase();
const oldNetwork = args[oldNetworkIdx + 1]?.toLowerCase();
const newNetwork = args[newNetworkIdx + 1]?.toLowerCase();
const deDup = args.includes('--deDup');
const dryRun = !args.includes('--doit');
if (chainIdx === -1 ||
    oldNetworkIdx === -1 ||
    newNetworkIdx === -1 ||
    !chain ||
    !oldNetwork ||
    !newNetwork) {
    usage('Missing required options.');
}
const batchSizeIdx = args.indexOf('--batchSize');
const batchSize = (batchSizeIdx > -1 && parseInt(args[batchSizeIdx + 1])) || 10000;
if (batchSize > -1 && isNaN(parseInt(args[batchSizeIdx + 1]))) {
    usage('batchSize must be an integer');
}
let quit = false;
process.on('SIGINT', () => {
    if (quit) {
        process.exit(1);
    }
    console.log('Caught interrupt signal');
    quit = true;
});
async function deleteOldAddress(e) {
    let [, c, n, w, a] = e.message.split('{')[1].split(':');
    c = c.trim().replace(/"/g, '').replace(/,/g, '');
    n = n.trim().replace(/"/g, '').replace(/,/g, '');
    w = w.trim().replace('ObjectId(', '').replace(')', '').replace(/'/g, '').replace(/,/g, '');
    a = a.replace('}', '').trim().replace(/"/g, '').replace(/,/g, '');
    console.log('Deleting dup:', c, n, w, a);
    const del1 = await walletAddress_1.WalletAddressStorage.collection.findOne({ chain, network: oldNetwork, wallet: new mongodb_1.ObjectID(w), address: a });
    const del2 = await walletAddress_1.WalletAddressStorage.collection.findOne({ chain, network: newNetwork, wallet: new mongodb_1.ObjectID(w), address: a });
    console.log(del1);
    console.log(del2);
    if (!!del1 && !!del2) {
        const del = await walletAddress_1.WalletAddressStorage.collection.deleteOne({ chain, network: oldNetwork, wallet: new mongodb_1.ObjectID(w), address: a });
        console.log(del.deletedCount);
    }
}
;
storage_1.Storage.start()
    .then(async () => {
    console.log('Connected to the database');
    const cnt1 = await wallet_1.WalletStorage.collection.countDocuments({ chain, network: oldNetwork });
    const cnt2 = await walletAddress_1.WalletAddressStorage.collection.countDocuments({ chain, network: oldNetwork });
    console.log(`${chain} ${oldNetwork} wallets:`, cnt1);
    console.log(`${chain} ${oldNetwork} walletAddresses:`, cnt2);
    if (dryRun) {
        return;
    }
    console.log('----------------------------------------');
    console.log(`Updating ${chain} ${oldNetwork} => ${newNetwork} wallets in 10 seconds...`);
    if (!quit)
        await (0, utils_1.wait)(10000);
    console.log(`Updating ${chain} ${oldNetwork} wallets...`);
    let wallets = await wallet_1.WalletStorage.collection.find({ chain, network: oldNetwork }).project({ _id: 1 }).limit(batchSize).toArray();
    let walletsUpdated = 0;
    while (wallets.length > 0 && !quit) {
        const res = await wallet_1.WalletStorage.collection.updateMany({ _id: { $in: wallets.map(c => c._id) } }, { $set: { network: newNetwork } });
        walletsUpdated += res.modifiedCount;
        process.stdout.write(`Updated ${walletsUpdated} wallets (${(walletsUpdated / cnt1 * 100).toFixed(2)}%)\r`);
        await (0, utils_1.wait)(250);
        wallets = await wallet_1.WalletStorage.collection.find({ chain, network: oldNetwork }).project({ _id: 1 }).limit(batchSize).toArray();
    }
    console.log(`Updating ${chain} ${oldNetwork} => ${newNetwork} walletAddresses in 10 seconds...`);
    if (!quit)
        await (0, utils_1.wait)(10000);
    console.log(`Updating ${chain} ${oldNetwork} walletAddresses...`);
    let walletAddresses = await walletAddress_1.WalletAddressStorage.collection.find({ chain, network: oldNetwork }).project({ _id: 1 }).limit(batchSize).toArray();
    let walletAddressesUpdated = 0;
    while (walletAddresses.length > 0 && !quit) {
        try {
            const res = await walletAddress_1.WalletAddressStorage.collection.updateMany({ _id: { $in: walletAddresses.map(c => c._id) } }, { $set: { network: newNetwork } });
            walletAddressesUpdated += res.modifiedCount;
        }
        catch (e) {
            if (e.message.includes('E11000') && deDup) {
                await deleteOldAddress(e);
            }
            else {
                throw e;
            }
        }
        process.stdout.write(`Updated ${walletAddressesUpdated} walletAddresses (${(walletAddressesUpdated / cnt2 * 100).toFixed(2)}%)\r`);
        await (0, utils_1.wait)(250);
        walletAddresses = await walletAddress_1.WalletAddressStorage.collection.find({ chain, network: oldNetwork }).project({ _id: 1 }).limit(batchSize).toArray();
    }
})
    .catch(console.error)
    .finally(() => {
    console.log('Closing the database connection');
    storage_1.Storage.stop();
});
//# sourceMappingURL=migrateTestnetWallets.js.map