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

const { state, saveState, loadState } = require("../shared/state");
const { setRuntimeDebug } = require("../shared/log");
const { refreshPrices } = require("../shared/prices");
const { refreshBalances } = require("../shared/balances");
const {
    $,
    showView,
    updateDebugBanner,
    setRenderMain,
    pushCurrentView,
    goBack,
    clearViewStack,
} = require("./views/helpers");
const { applyTheme } = require("./theme");
// Views that can be fully re-rendered from persisted state. All others fall
// back to the nearest restorable parent; see the module for why the
// secret-bearing views are absent.
const { RESTORABLE_VIEWS } = require("./restorableViews");

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");

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.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);
    },
};

function needsAddress(view) {
    return (
        view === "address" ||
        view === "address-token" ||
        view === "receive" ||
        view === "transaction"
    );
}

function hasValidAddress() {
    return (
        state.selectedWallet !== null &&
        state.selectedAddress !== null &&
        state.wallets[state.selectedWallet] &&
        state.wallets[state.selectedWallet].addresses[state.selectedAddress]
    );
}

function restoreView() {
    const view = state.currentView;
    if (!view || !RESTORABLE_VIEWS.has(view)) {
        return fallbackView();
    }

    if (needsAddress(view) && !hasValidAddress()) {
        return fallbackView();
    }

    if (view === "address-token" && !state.selectedToken) {
        return fallbackView();
    }

    switch (view) {
        case "address":
            addressDetail.show();
            break;
        case "address-token":
            addressToken.show();
            break;
        case "receive":
            receive.show();
            break;
        case "settings":
            settings.show();
            break;
        case "settings-addtoken":
            settingsAddToken.show();
            break;
        case "confirm-tx":
            if (state.viewData && state.viewData.pendingTx) {
                confirmTx.restore();
            } else {
                fallbackView();
            }
            break;
        case "transaction":
            if (state.viewData && state.viewData.tx) {
                transactionDetail.render();
            } else {
                fallbackView();
            }
            break;
        case "wait-tx":
            // Resumes the receipt poll from the persisted broadcast time.
            if (!txStatus.restoreWait()) {
                fallbackView();
            }
            break;
        case "success-tx":
            if (state.viewData && state.viewData.hash) {
                txStatus.renderSuccess();
            } else {
                fallbackView();
            }
            break;
        case "error-tx":
            if (state.viewData && state.viewData.message) {
                txStatus.renderError();
            } else {
                fallbackView();
            }
            break;
        default:
            fallbackView();
            break;
    }
}

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

async function init() {
    await loadState();
    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) {
        approval.show(approvalId);
        showView("approve-site");
        return;
    }

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

    setRenderMain(renderWalletList);

    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);
