const {
    $,
    showView,
    updateDebugBanner,
    showFlash,
    escapeHtml,
    displaySymbol,
    flashCopyFeedback,
    goBack,
    pushCurrentView,
} = require("./helpers");
const { applyTheme } = require("../theme");
const {
    DUST_THRESHOLD_MESSAGE,
    parseDustThresholdGwei,
} = require("../dustThreshold");
const { state, saveState, currentNetwork } = require("../../shared/state");
const { onChainSwitch } = require("../../shared/chainSwitch");
const { log, debugFetch, setRuntimeDebug } = require("../../shared/log");
const deleteWallet = require("./deleteWallet");
const showPhrase = require("./showPhrase");
const { walletHasRecoveryPhrase } = require("../../shared/wallet");
const {
    BUILD_VERSION,
    BUILD_LICENSE,
    BUILD_AUTHOR,
    BUILD_COMMIT,
    BUILD_DATE,
    GITEA_COMMIT_URL,
} = require("../../shared/buildInfo");

const { notify } = require("../../shared/browserApi");

let versionClickCount = 0;
let versionClickTimer = null;

function renderSiteList(containerId, siteMap, stateKey) {
    const container = $(containerId);
    const hostnames = [...new Set(Object.values(siteMap).flat())];
    if (hostnames.length === 0) {
        container.innerHTML = '<p class="text-xs text-muted">None</p>';
        return;
    }
    let html = "";
    hostnames.forEach((hostname) => {
        html += `<div class="flex justify-between items-center text-xs py-1 border-b border-border-light">`;
        // A hostname the URL parser produced cannot carry a delimiter, so
        // this is escaped for the rule rather than for a known hole — the
        // rule being that nothing reaches innerHTML unescaped.
        html += `<span>${escapeHtml(hostname)}</span>`;
        html += `<button class="btn-remove-site border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-key="${escapeHtml(stateKey)}" data-hostname="${escapeHtml(hostname)}">[x]</button>`;
        html += `</div>`;
    });
    container.innerHTML = html;
    container.querySelectorAll(".btn-remove-site").forEach((btn) => {
        btn.addEventListener("click", async () => {
            const key = btn.dataset.key;
            const host = btn.dataset.hostname;
            for (const addr of Object.keys(state[key])) {
                state[key][addr] = state[key][addr].filter((h) => h !== host);
                if (state[key][addr].length === 0) {
                    delete state[key][addr];
                }
            }
            await saveState();
            notify({ type: "AUTISTMASK_REMOVE_SITE" });
            renderSiteList(containerId, state[key], key);
        });
    });
}

function renderTrackedTokens() {
    const container = $("settings-tracked-tokens");
    if (state.trackedTokens.length === 0) {
        container.innerHTML = '<p class="text-xs text-muted">None</p>';
        return;
    }
    let html = "";
    state.trackedTokens.forEach((token, idx) => {
        const sym = escapeHtml(displaySymbol(token.symbol));
        const label = token.name
            ? escapeHtml(token.name) + " (" + sym + ")"
            : sym;
        html += `<div class="flex justify-between items-center text-xs py-1 border-b border-border-light">`;
        html += `<span>${label}</span>`;
        html += `<button class="btn-remove-token border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-idx="${idx}">[x]</button>`;
        html += `</div>`;
    });
    container.innerHTML = html;
    container.querySelectorAll(".btn-remove-token").forEach((btn) => {
        btn.addEventListener("click", async () => {
            const idx = parseInt(btn.dataset.idx, 10);
            state.trackedTokens.splice(idx, 1);
            await saveState();
            renderTrackedTokens();
        });
    });
}

function renderWalletListSettings() {
    const container = $("settings-wallet-list");
    if (state.wallets.length === 0) {
        container.innerHTML = '<p class="text-xs text-muted">No wallets.</p>';
        return;
    }
    let html = "";
    state.wallets.forEach((wallet, idx) => {
        const name = escapeHtml(wallet.name || "Wallet " + (idx + 1));
        html += `<div class="flex justify-between items-center text-xs py-1 border-b border-border-light">`;
        html += `<span class="settings-wallet-name cursor-pointer underline decoration-dashed" data-idx="${idx}">${name}</span>`;
        html += `<span class="flex items-center gap-1 flex-shrink-0">`;
        // Key and xprv wallets have no recovery phrase, so they are never
        // offered the action at all.
        if (walletHasRecoveryPhrase(wallet)) {
            html += `<button class="btn-show-phrase border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-idx="${idx}" title="Show recovery phrase">[recovery phrase]</button>`;
        }
        html += `<button class="btn-delete-wallet border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-idx="${idx}">[x]</button>`;
        html += `</span>`;
        html += `</div>`;
    });
    container.innerHTML = html;
    container.querySelectorAll(".btn-delete-wallet").forEach((btn) => {
        btn.addEventListener("click", () => {
            const idx = parseInt(btn.dataset.idx, 10);
            pushCurrentView();
            deleteWallet.show(idx);
        });
    });

    container.querySelectorAll(".btn-show-phrase").forEach((btn) => {
        btn.addEventListener("click", () => {
            const idx = parseInt(btn.dataset.idx, 10);
            // No pushCurrentView() here: showPhrase.show() refuses
            // non-HD wallets and pushes only when it navigates.
            showPhrase.show(idx);
        });
    });

    // Inline rename on click
    container.querySelectorAll(".settings-wallet-name").forEach((span) => {
        span.addEventListener("click", () => {
            const idx = parseInt(span.dataset.idx, 10);
            const wallet = state.wallets[idx];
            const input = document.createElement("input");
            input.type = "text";
            input.className =
                "border border-border p-0 text-xs bg-bg text-fg w-full";
            input.value = wallet.name || "Wallet " + (idx + 1);
            span.replaceWith(input);
            input.focus();
            input.select();
            const finish = async () => {
                const val = input.value.trim();
                if (val && val !== wallet.name) {
                    wallet.name = val;
                    await saveState();
                }
                renderWalletListSettings();
            };
            input.addEventListener("blur", finish);
            input.addEventListener("keydown", (e) => {
                if (e.key === "Enter") input.blur();
                if (e.key === "Escape") {
                    input.value = wallet.name || "Wallet " + (idx + 1);
                    input.blur();
                }
            });
        });
    });
}

function show() {
    $("settings-rpc").value = state.rpcUrl;
    $("settings-blockscout").value = state.blockscoutUrl;
    $("settings-network").value = state.networkId;
    renderTrackedTokens();
    renderSiteLists();
    renderWalletListSettings();

    // Populate About well
    $("about-license").textContent = BUILD_LICENSE;
    // Show only the name part of the author field (strip email)
    const authorName = BUILD_AUTHOR.replace(/\s*<[^>]+>/, "");
    $("about-author").textContent = authorName;
    $("about-version").textContent = BUILD_VERSION;
    $("about-release-date").textContent = BUILD_DATE;
    $("about-commit-link").textContent = BUILD_COMMIT;
    $("about-commit-link").href = GITEA_COMMIT_URL;

    // Reset version click counter each time settings opens
    versionClickCount = 0;

    // Show debug well if debug mode is already enabled
    const debugWell = $("settings-debug-well");
    if (state.debugMode) {
        debugWell.style.display = "";
    } else {
        debugWell.style.display = "none";
    }
    $("settings-debug-mode").checked = state.debugMode;

    showView("settings");
}

function renderSiteLists() {
    renderSiteList(
        "settings-allowed-sites",
        state.allowedSites,
        "allowedSites",
    );
    renderSiteList("settings-denied-sites", state.deniedSites, "deniedSites");
}

function init(ctx) {
    deleteWallet.init(ctx);
    showPhrase.init();

    $("btn-save-rpc").addEventListener("click", async () => {
        const url = $("settings-rpc").value.trim();
        if (!url) {
            showFlash("Please enter an RPC URL.");
            return;
        }
        showFlash("Testing endpoint...");
        try {
            const resp = await debugFetch(url, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    jsonrpc: "2.0",
                    id: 1,
                    method: "eth_chainId",
                    params: [],
                }),
            });
            const json = await resp.json();
            if (json.error) {
                log.errorf("RPC validation error:", json.error);
                showFlash("Endpoint returned error: " + json.error.message);
                return;
            }
            const net = currentNetwork();
            if (json.result !== net.chainId) {
                showFlash(
                    "Wrong network (expected " +
                        net.name +
                        ", got chain " +
                        json.result +
                        ").",
                );
                return;
            }
        } catch (e) {
            log.errorf("RPC validation fetch failed:", e.message);
            showFlash("Could not reach endpoint.");
            return;
        }
        state.rpcUrl = url;
        await saveState();
        showFlash("Saved.");
    });

    $("btn-save-blockscout").addEventListener("click", async () => {
        const url = $("settings-blockscout").value.trim();
        if (!url) {
            showFlash("Please enter a Blockscout API URL.");
            return;
        }
        showFlash("Testing endpoint...");
        try {
            const resp = await debugFetch(url + "/stats");
            if (!resp.ok) {
                showFlash("Endpoint returned HTTP " + resp.status + ".");
                return;
            }
        } catch (e) {
            log.errorf("Blockscout validation failed:", e.message);
            showFlash("Could not reach endpoint.");
            return;
        }
        state.blockscoutUrl = url;
        await saveState();
        showFlash("Saved.");
    });

    const networkSelect = $("settings-network");
    networkSelect.addEventListener("change", async () => {
        const newId = networkSelect.value;
        const net = await onChainSwitch(newId);
        $("settings-rpc").value = state.rpcUrl;
        $("settings-blockscout").value = state.blockscoutUrl;
        showFlash("Switched to " + net.name + ".");
    });

    $("settings-show-zero-balances").checked = state.showZeroBalanceTokens;
    $("settings-show-zero-balances").addEventListener("change", async () => {
        state.showZeroBalanceTokens = $("settings-show-zero-balances").checked;
        await saveState();
    });

    $("settings-theme").value = state.theme;
    $("settings-theme").addEventListener("change", async () => {
        state.theme = $("settings-theme").value;
        await saveState();
        applyTheme(state.theme);
    });

    $("settings-hide-spoofed-symbols").checked = state.hideSpoofedSymbols;
    $("settings-hide-spoofed-symbols").addEventListener("change", async () => {
        state.hideSpoofedSymbols = $("settings-hide-spoofed-symbols").checked;
        await saveState();
    });

    $("settings-hide-low-holders").checked = state.hideLowHolderTokens;
    $("settings-hide-low-holders").addEventListener("change", async () => {
        state.hideLowHolderTokens = $("settings-hide-low-holders").checked;
        await saveState();
    });

    $("settings-hide-fraud-contracts").checked = state.hideFraudContracts;
    $("settings-hide-fraud-contracts").addEventListener("change", async () => {
        state.hideFraudContracts = $("settings-hide-fraud-contracts").checked;
        await saveState();
    });

    $("settings-hide-dust").checked = state.hideDustTransactions;
    $("settings-hide-dust").addEventListener("change", async () => {
        state.hideDustTransactions = $("settings-hide-dust").checked;
        await saveState();
    });

    $("settings-dust-threshold").value = state.dustThresholdGwei;
    $("settings-dust-threshold").addEventListener("change", async () => {
        const val = parseDustThresholdGwei($("settings-dust-threshold").value);
        // Rejected input is never coerced. The field is put back to the
        // stored threshold so it never shows a value the wallet is not
        // using, and the message says what the field wants so the snap-back
        // is explained rather than silent.
        if (val === null) {
            showFlash(DUST_THRESHOLD_MESSAGE);
        } else {
            state.dustThresholdGwei = val;
            await saveState();
        }
        $("settings-dust-threshold").value = state.dustThresholdGwei;
    });

    $("settings-utc-timestamps").checked = state.utcTimestamps;
    $("settings-utc-timestamps").addEventListener("change", async () => {
        state.utcTimestamps = $("settings-utc-timestamps").checked;
        await saveState();
    });

    $("btn-main-add-wallet").addEventListener("click", ctx.showAddWalletView);

    $("btn-settings-add-token").addEventListener(
        "click",
        ctx.showSettingsAddTokenView,
    );

    // Bright saturated colors for easter egg flashes (clicks 6–10)
    const easterEggColors = [
        "#ff0055", // hot pink
        "#00cc44", // vivid green
        "#3366ff", // electric blue
        "#ff9900", // bright orange
        "#aa00ff", // vivid purple
    ];

    // Easter egg: click version 10 times to reveal the debug well.
    // Each click does a copy-flash animation. After 5 clicks, each
    // additional click flashes a different bright saturated color.
    $("about-version").addEventListener("click", () => {
        versionClickCount++;
        clearTimeout(versionClickTimer);
        // Reset counter if user stops clicking for 3 seconds
        versionClickTimer = setTimeout(() => {
            versionClickCount = 0;
        }, 3000);

        const el = $("about-version");

        if (versionClickCount > 5) {
            // Colored flash for clicks 6–10
            const colorIdx = versionClickCount - 6;
            const color = easterEggColors[colorIdx % easterEggColors.length];
            el.classList.remove("copy-flash-fade");
            el.style.backgroundColor = color;
            el.style.color = "#ffffff";
            setTimeout(() => {
                el.style.backgroundColor = "";
                el.style.color = "";
                el.classList.add("copy-flash-fade");
                setTimeout(() => {
                    el.classList.remove("copy-flash-fade");
                }, 275);
            }, 75);
        } else {
            // Standard copy-flash for clicks 1–5
            flashCopyFeedback(el);
        }

        if (versionClickCount >= 10) {
            versionClickCount = 0;
            clearTimeout(versionClickTimer);
            $("settings-debug-well").style.display = "";
        }
    });

    // Debug mode toggle — update runtime flag, persist, and re-render banner
    $("settings-debug-mode").addEventListener("change", async () => {
        state.debugMode = $("settings-debug-mode").checked;
        setRuntimeDebug(state.debugMode);
        await saveState();
        updateDebugBanner(state.currentView);
    });

    // Sync runtime debug flag on init
    setRuntimeDebug(state.debugMode);

    $("btn-settings-back").addEventListener("click", () => {
        goBack();
    });
}

module.exports = { init, show, renderSiteLists };
