// Private key export for a single address.
//
// The key controls the address outright — anyone holding it can move every
// token in it, from any device, forever — so this screen is handled under
// the same rules as the recovery phrase screen (./showPhrase.js):
//
//   1. Nothing is decrypted, no key is derived, and nothing is written into
//      the DOM until decryptWithPassword has accepted the password.
//   2. Leaving the screen by any path wipes it, via the onViewLeave hook,
//      and a decrypt still in flight when that happens is discarded
//      instead of written (revealGeneration).
//   3. The key never reaches the logger. This module deliberately does not
//      import src/shared/log.js.
//
// The key is also never assigned to `state`, so it cannot be persisted to
// extension storage, and "export-privkey" is excluded from RESTORABLE_VIEWS
// so the popup can never reopen onto it.

const {
    $,
    showView,
    showFlash,
    flashCopyFeedback,
    goBack,
    onViewLeave,
    pushCurrentView,
    renderAddressHtml,
    attachCopyHandlers,
} = require("./helpers");
const { state } = require("../../shared/state");
const { decryptWithPassword } = require("../../shared/vault");
const { getSignerForAddress } = require("../../shared/wallet");
const makeBlockie = require("ethereum-blockies-base64");

const VIEW = "export-privkey";

let walletIndex = null;
let addressIndex = null;

// Bumped by every clear(), which is what leaving the screen runs. reveal()
// captures it before awaiting the decrypt and refuses to touch the DOM if
// it has moved: a decrypt still in flight when the screen is left would
// otherwise write the key *after* the wipe, with nothing scheduled to wipe
// it again, leaving it in the hidden view for the life of the popup.
let revealGeneration = 0;

// True only if the reveal that captured `generation` is still the live one:
// the screen has not been left, cleared, or re-entered for another address
// since it started.
function isCurrentReveal(generation) {
    return (
        generation === revealGeneration &&
        walletIndex !== null &&
        addressIndex !== null &&
        state.currentView === VIEW
    );
}

function fail(message) {
    $("export-privkey-flash").textContent = message;
    $("export-privkey-flash").style.visibility = "visible";
}

// Wipe every trace of the key and drop the address selection. Safe to call
// when nothing was ever revealed, and safe to call twice.
function clear() {
    walletIndex = null;
    addressIndex = null;
    revealGeneration += 1;
    $("export-privkey-value").textContent = "";
    $("export-privkey-password").value = "";
    $("export-privkey-result").classList.add("hidden");
    $("export-privkey-password-section").classList.remove("hidden");
    $("export-privkey-flash").textContent = "";
    $("export-privkey-flash").style.visibility = "hidden";
}

function show(walletIdx, addrIdx) {
    const wallet = state.wallets[walletIdx];
    const addr = wallet && wallet.addresses[addrIdx];
    if (!addr) {
        showFlash("That address is no longer available.");
        return;
    }
    clear();
    walletIndex = walletIdx;
    addressIndex = addrIdx;

    const blockieEl = $("export-privkey-jazzicon");
    blockieEl.innerHTML = "";
    const img = document.createElement("img");
    img.src = makeBlockie(addr.address);
    img.width = 48;
    img.height = 48;
    img.style.imageRendering = "pixelated";
    img.style.borderRadius = "50%";
    blockieEl.appendChild(img);

    $("export-privkey-title").textContent =
        wallet.name + " — Address " + (addrIdx + 1);
    const addrContainer = $("export-privkey-dot").parentElement;
    addrContainer.innerHTML = renderAddressHtml(addr.address);
    attachCopyHandlers(addrContainer);

    // Pushed here rather than by the caller: this function can return
    // without navigating, and a push that happened anyway would leave an
    // entry on the stack that no screen transition matches.
    pushCurrentView();
    showView(VIEW);
}

async function reveal() {
    const password = $("export-privkey-password").value;
    if (!password) {
        fail("Please enter your password.");
        return;
    }
    if (walletIndex === null) {
        fail("No address is selected.");
        return;
    }
    const wallet = state.wallets[walletIndex];

    const btn = $("btn-export-privkey-confirm");
    btn.disabled = true;
    btn.classList.add("text-muted");
    const generation = revealGeneration;
    try {
        const secret = await decryptWithPassword(
            wallet.encryptedSecret,
            password,
        );
        // The only suspension point in this view, and the gate on the only
        // place a secret is written: if the screen was left while the
        // decrypt ran, the wipe has already happened, so the key is not
        // even derived, let alone written.
        if (!isCurrentReveal(generation)) return;
        const signer = getSignerForAddress(wallet, addressIndex, secret);
        $("export-privkey-password").value = "";
        $("export-privkey-password-section").classList.add("hidden");
        $("export-privkey-value").textContent = signer.privateKey;
        $("export-privkey-result").classList.remove("hidden");
        $("export-privkey-flash").textContent = "";
        $("export-privkey-flash").style.visibility = "hidden";
    } catch {
        if (!isCurrentReveal(generation)) return;
        fail("That password is incorrect. Please try again.");
    } finally {
        btn.disabled = false;
        btn.classList.remove("text-muted");
    }
}

function init() {
    onViewLeave(VIEW, clear);

    // No wipe here: goBack() routes through showView(), which runs the
    // leave hook. A per-button wipe would only cover this one path.
    $("btn-export-privkey-back").addEventListener("click", () => {
        goBack();
    });

    $("btn-export-privkey-confirm").addEventListener("click", reveal);

    $("export-privkey-value").addEventListener("click", () => {
        const key = $("export-privkey-value").textContent;
        if (!key) return;
        navigator.clipboard.writeText(key);
        showFlash("Copied!");
        flashCopyFeedback($("export-privkey-value"));
    });
}

module.exports = { init, show };
