#!/usr/bin/env node
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const readline_1 = __importDefault(require("readline"));
const util_1 = __importDefault(require("util"));
const CWC = __importStar(require("@bitpay-labs/crypto-wallet-core"));
const block_js_1 = require("../build/src/models/block.js");
const transaction_js_1 = require("../build/src/models/transaction.js");
const storage_js_1 = require("../build/src/services/storage.js");
let shutdown = false;
process.on('SIGINT', () => {
    if (shutdown) {
        console.log('Force exiting...');
        process.exit(1);
    }
    shutdown = true;
    console.log('Gracefully shutting down...');
});
function usage(errMsg) {
    console.log('USAGE: ./fixEvmTxToFromAddressesCase.js <options>');
    console.log('OPTIONS:');
    console.log('  --chain <value>          REQUIRED - e.g. ETH, MATIC...');
    console.log('  --network <value>        REQUIRED - e.g. mainnet, sepolia, regtest...');
    console.log('  --startHeight <value>    REQUIRED Block height to start from');
    console.log('  --endHeight <value>      REQUIRED Block height to stop at');
    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 networkIdx = args.indexOf('--network');
const startHeightIdx = args.indexOf('--startHeight');
const endHeightIdx = args.indexOf('--endHeight');
const chain = args[chainIdx + 1]?.toUpperCase();
const network = args[networkIdx + 1]?.toLowerCase();
const startHeight = parseInt(args[startHeightIdx + 1]);
const endHeight = parseInt(args[endHeightIdx + 1]);
if (chainIdx === -1 || networkIdx === -1 || startHeightIdx === -1 || endHeightIdx === -1) {
    usage('Missing required options.');
}
if (!chain || !network || isNaN(startHeight) || isNaN(endHeight)) {
    usage('Invalid option value(s).');
}
if (startHeight < 0) {
    usage('startHeight must be greater than or equal to 0.');
}
if (endHeight <= startHeight) {
    usage('endHeight must be greater than startHeight.');
}
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
console.log('Connecting to database...');
storage_js_1.Storage.start()
    .then(async () => {
    console.log('Finding local tip...');
    const lastBlockNum = Math.min(endHeight, (await block_js_1.BitcoinBlockStorage.getLocalTip({ chain, network }))?.height ?? Infinity);
    const totalBlockCount = lastBlockNum - startHeight + 1;
    console.log(`Updating ${totalBlockCount} block's worth of transactions.`);
    const ans = await util_1.default.promisify(rl.question).call(rl, 'Would you like to continue? (Y/n) ');
    if (ans?.toLowerCase() === 'n') {
        return;
    }
    let thisBlockNum = startHeight;
    let countModified = 0;
    let countRunning = 0;
    do {
        if (shutdown) {
            return;
        }
        const txStream = transaction_js_1.TransactionStorage.collection.find({ chain, network, blockHeight: thisBlockNum }).addCursorFlag('noCursorTimeout', true);
        for await (const tx of txStream) {
            if (shutdown) {
                return;
            }
            const res = await transaction_js_1.TransactionStorage.collection.updateOne({ _id: tx._id }, {
                $set: {
                    to: tx.to ? CWC.Web3.utils.toChecksumAddress(tx.to) : '',
                    from: tx.from ? CWC.Web3.utils.toChecksumAddress(tx.from) : ''
                }
            });
            if (!res.result.ok) {
                console.error(`Failed to update tx ${tx.txid}:`, res);
            }
            countModified += res.modifiedCount;
            if (countRunning % 100 === 0) {
                const percent = ((thisBlockNum - startHeight) / totalBlockCount * 100).toFixed(4);
                process.stdout.write(`Processing block ${thisBlockNum} (${percent}%) -- (${countModified} txs updated)...         \r`);
                await new Promise(r => setTimeout(r, 20));
            }
            countRunning++;
        }
        thisBlockNum++;
    } while (thisBlockNum <= lastBlockNum);
    console.log(`\nUpdated ${countModified} transactions.`);
})
    .catch(console.error)
    .finally(() => {
    rl.close();
    storage_js_1.Storage.stop();
});
//# sourceMappingURL=fixEvmTxToFromAddressesCase.js.map