// AutistMask popup entry point.
// Loads state, initializes views, triggers first render.

const { state, saveState, loadState } = require("../shared/state");
const { StateUnusableError } = require("../shared/stateSchema");
const { setRuntimeDebug } = require("../shared/log");
const { refreshPrices } = require("../shared/prices");
const { refreshBalances } = require("../shared/balances");
const {
    $,
    showView,
    updateDebugBanner,
    setBackRenderer,
    pushCurrentView,
    goBack,
} = require("./views/helpers");
const { applyTheme } = require("./theme");
// Renders a view the popup lands on without having navigated to it forward:
// on restore here, and on Back. Only the views that can be fully re-rendered
// from persisted state (RESTORABLE_VIEWS, src/shared/restorableViews.js) go
// through it; anything else falls back to the nearest restorable parent.
const { renderView, makeBackRenderer } = require("./viewRouter");

const home = require("./views/home");
const welcome = require("./views/welcome");
const addWallet = require("./views/addWallet");
const addressDetail = require("./views/addressDetail");
const addressToken = require("./views/addressToken");
const send = require("./views/send");
const confirmTx = require("./views/confirmTx");
const txStatus = require("./views/txStatus");
const transactionDetail = require("./views/transactionDetail");
const receive = require("./views/receive");
const addToken = require("./views/addToken");
const settings = require("./views/settings");
const settingsAddToken = require("./views/settingsAddToken");
const deleteAddress = require("./views/deleteAddress");
const approval = require("./views/approval");
const stateRecovery = require("./views/stateRecovery");

function renderWalletList() {
    home.render(ctx);
}

let refreshInFlight = false;

async function doRefreshAndRender() {
    if (refreshInFlight) return;
    refreshInFlight = true;
    try {
        await Promise.all([
            refreshPrices(),
            refreshBalances(
                state.wallets,
                state.rpcUrl,
                state.blockscoutUrl,
                state.trackedTokens,
                state.networkId,
            ),
        ]);
        state.lastBalanceRefresh = Date.now();
        await saveState();
        renderWalletList();
    } finally {
        refreshInFlight = false;
    }
}

const ctx = {
    renderWalletList,
    doRefreshAndRender,
    showAddWalletView: () => {
        pushCurrentView();
        addWallet.show();
    },
    showAddressDetail: () => {
        pushCurrentView();
        addressDetail.show();
    },
    showAddressToken: () => {
        pushCurrentView();
        addressToken.show();
    },
    showAddTokenView: () => {
        pushCurrentView();
        addToken.show();
    },
    showConfirmTx: (txInfo) => {
        pushCurrentView();
        confirmTx.show(txInfo);
    },
    showReceive: () => {
        pushCurrentView();
        receive.show();
    },
    showTransactionDetail: (tx) => {
        pushCurrentView();
        transactionDetail.show(tx);
    },
    showSettingsView: () => {
        pushCurrentView();
        settings.show();
    },
    showSettingsAddTokenView: () => {
        pushCurrentView();
        settingsAddToken.show();
    },
    showDeleteAddress: (walletIdx, addrIdx) => {
        pushCurrentView();
        deleteAddress.show(walletIdx, addrIdx);
    },
};

// The view modules the router renders through, keyed as it expects them.
const viewModules = {
    main: { show: () => fallbackView() },
    addressDetail,
    addressToken,
    receive,
    settings,
    settingsAddToken,
    confirmTx,
    transactionDetail,
    txStatus,
};

function restoreView() {
    if (!renderView(state.currentView, state, viewModules)) {
        fallbackView();
    }
}

function fallbackView() {
    renderWalletList();
    showView("main");
}

async function init() {
    try {
        await loadState();
    } catch (e) {
        // A profile this build cannot read is the one failure that must not
        // fall through to the rest of init(). It used to: the load "succeeded"
        // on a record nothing had validated, and the first dereference below
        // threw, leaving a popup with no view, no message and no control on
        // it, and no way out of the wallet from inside the product
        // (https://git.eeqj.de/sneak/AutistMask/issues/311). Now the load
        // refuses, and this is the screen that says so.
        if (e instanceof StateUnusableError) {
            stateRecovery.show(e);
            return;
        }
        throw e;
    }
    applyTheme(state.theme);

    // Sync runtime debug flag from persisted state before first render
    setRuntimeDebug(state.debugMode);

    // Create the debug/testnet banner if needed (uses runtime debug state)
    updateDebugBanner();

    // Auto-default active address
    if (
        state.activeAddress === null &&
        state.wallets.length > 0 &&
        state.wallets[0].addresses.length > 0
    ) {
        state.activeAddress = state.wallets[0].addresses[0].address;
        await saveState();
    }

    // Always init approval and txStatus — they may run in the approval popup window
    approval.init(ctx);
    txStatus.init(ctx);

    // Check for approval mode
    const params = new URLSearchParams(window.location.search);
    const approvalId = params.get("approval");
    if (approvalId) {
        // Deliberately not awaited, and deliberately not .catch()ed. show()
        // is async, so a throw past its first await surfaces as an unhandled
        // rejection rather than an uncaught error — measured as still failing
        // the run on both harnesses (Playwright `pageerror`, and the Firefox
        // driver's console-service drain), so nothing is lost by leaving it
        // on that path.
        approval.show(approvalId);
        showView("approve-site");
        return;
    }

    $("btn-settings").addEventListener("click", () => {
        if (
            !document
                .getElementById("view-settings")
                .classList.contains("hidden")
        ) {
            goBack();
            return;
        }
        pushCurrentView();
        settings.show();
    });

    setBackRenderer(makeBackRenderer(state, viewModules));

    welcome.init(ctx);
    addWallet.init(ctx);
    home.init(ctx);
    addressDetail.init(ctx);
    addressToken.init(ctx);
    send.init(ctx);
    confirmTx.init(ctx);
    transactionDetail.init(ctx);
    receive.init(ctx);
    addToken.init(ctx);
    settings.init(ctx);
    settingsAddToken.init(ctx);
    deleteAddress.init(ctx);

    if (!state.hasWallet) {
        showView("welcome");
    } else {
        renderWalletList();
        restoreView();
        doRefreshAndRender();
        setInterval(doRefreshAndRender, 10000);
    }
}

document.addEventListener("DOMContentLoaded", init);
