// Confirmation screen for removing one address from a wallet that derives
// its addresses from an extended key.
//
// No password is asked for, unlike delete-wallet. A password gates the
// disclosure or destruction of a secret, and this does neither: the address
// is derived from key material the wallet still holds, so removing it only
// stops the wallet tracking it. An explicit confirmation screen is the
// proportionate treatment.

const {
    $,
    showView,
    showFlash,
    escapeHtml,
    goBack,
    renderAddressHtml,
    attachCopyHandlers,
    addressHoldsFunds,
    balanceLinesForAddress,
} = require("./helpers");
const { formatAddressTotal, getAddressValue } = require("../../shared/prices");
const { walletHasRecoveryPhrase } = require("../../shared/wallet");
const { state, saveState } = require("../../shared/state");
const {
    canRemoveAddress,
    removeAddressFromState,
    broadcastActiveChanged,
} = require("../../shared/walletDelete");

// The wallet and address indices this screen is confirming, or null when it
// is not confirming anything.
let target = null;
let ctx = null;

function setFlash(msg) {
    const el = $("delete-address-flash");
    el.textContent = msg;
    el.style.visibility = msg ? "visible" : "hidden";
}

// What it actually takes to get the address back, which is not what the
// screen used to claim.
//
// Neither obvious route works: "+" derives the next unused index, because
// wallet.nextIndex is a high-water mark and is deliberately not rewound; and
// re-importing this wallet's key material is refused as a duplicate by
// findWalletByXpub() for as long as the wallet is here. What remains is to
// delete the whole wallet in Settings — which destroys the stored secret,
// with or without the password — and import again, after which
// scanForAddresses() rediscovers the address only if it has on-chain
// activity. An address that was never used is not found by that scan, and
// the copy must not imply otherwise.
//
// The noun follows the wallet: an xprv wallet holds no recovery phrase, and
// this screen is offered on xprv wallets too.
function recoveryPathText(wallet) {
    const secret = walletHasRecoveryPhrase(wallet)
        ? "recovery phrase"
        : "extended private key";
    return (
        "Getting the address back into this list is not easy, so be sure. " +
        "Adding an address derives the next unused one, not this one, and " +
        "importing this " +
        secret +
        " again is refused while this wallet is still here. The way back is " +
        "to delete the whole wallet in Settings, which destroys the stored " +
        secret +
        ", and then import that " +
        secret +
        " again. The scan that follows only finds addresses that have " +
        "on-chain activity, so an address that has never been used is not " +
        "found by it."
    );
}

// The balance warning, or a blank line when the address holds nothing.
//
// A balance is a reason to be careful, not a reason to refuse: the funds are
// at the address, not in this list, and stay there either way.
//
// "Holds" means ETH or any ERC-20 the wallet knows about — an address with no
// ETH and a five-figure stablecoin position must not get the blank line on
// the one screen whose job is to warn. The sentence names no figure of its
// own: the rendered lines round to four decimals, so a sentence built from a
// rounded number would report "0.0000 ETH" for an address holding real money.
// The lines below it carry the amounts, in the same format as Home and
// AddressDetail, followed by the USD total when there is one to give — no
// total line at all on testnet or before the first price fetch, and no figure
// when every holding here is one with no price, since "$0.00" directly under
// "This address holds a balance." is a contradiction.
function balanceWarningHtml(addr) {
    if (!addressHoldsFunds(addr)) return "&nbsp;";
    const line = formatAddressTotal(getAddressValue(addr));
    const total = line
        ? `<div class="text-xs text-muted mt-1">${escapeHtml(line)}</div>`
        : "";
    return (
        `<p class="mb-1">This address holds a balance. Removing it does not ` +
        `move or spend anything; the balance stays at the address.</p>` +
        balanceLinesForAddress(addr, state.trackedTokens, false) +
        total
    );
}

function show(walletIdx, addrIdx) {
    const wallet = state.wallets[walletIdx];
    const addr = wallet && wallet.addresses[addrIdx];
    if (!addr) return;
    target = { walletIdx, addrIdx };

    $("delete-address-label").textContent = "Address " + (addrIdx + 1);
    $("delete-address-wallet-name").textContent =
        wallet.name || "Wallet " + (walletIdx + 1);

    const value = $("delete-address-value");
    value.innerHTML = renderAddressHtml(addr.address, {
        ensName: addr.ensName,
    });
    attachCopyHandlers(value);

    $("delete-address-recovery").textContent = recoveryPathText(wallet);
    $("delete-address-balance").innerHTML = balanceWarningHtml(addr);

    setFlash("");
    showView("delete-address-confirm");
}

function init(_ctx) {
    ctx = _ctx;

    $("btn-delete-address-back").addEventListener("click", () => {
        target = null;
        goBack();
    });

    $("btn-delete-address-confirm").addEventListener("click", async () => {
        if (target === null) {
            setFlash("No address is selected for removal.");
            return;
        }

        const { walletIdx, addrIdx } = target;
        if (!canRemoveAddress(state.wallets[walletIdx])) {
            setFlash(
                "This address cannot be removed, because a wallet always " +
                    "keeps at least one address.",
            );
            return;
        }

        const { removed, activeAddressChanged } = removeAddressFromState(
            state,
            walletIdx,
            addrIdx,
        );
        if (!removed) {
            setFlash("This address could not be removed.");
            return;
        }

        target = null;
        // Save before broadcasting: the background reads the active address
        // back out of storage to build accountsChanged.
        await saveState();
        if (activeAddressChanged) broadcastActiveChanged();

        ctx.renderWalletList();
        goBack();
        showFlash("Address removed.");
    });
}

// recoveryPathText and balanceWarningHtml are exported so the two pieces of
// copy that carry the screen's substance can be tested without a DOM; show()
// is a one-line assignment for each.
module.exports = { init, show, recoveryPathText, balanceWarningHtml };
