/**
 * Site-wide automatic wallet connection hub.
 * Supports injected wallets (MetaMask, Coinbase, Trust, etc.) + WalletConnect v2 QR.
 * Manual phrase/key import on connect-wallet.php is separate and untouched.
 */
(function () {
    'use strict';

    const cfg = window.WALLET_HUB_CONFIG || {};
    const STORAGE_KEY = 'wallet_hub_v1';

    let activeProvider = null;
    let ethersProvider = null;
    let wcProvider = null;
    let wcInitPromise = null;
    let qrPairingPromise = null;
    let wcConnectPromise = null;
    let lastQrUri = null;

    const state = {
        connected: false,
        address: null,
        chainId: null,
        walletId: null,
        providerLabel: null,
    };

    const WALLET_LABELS = {
        metamask: 'MetaMask',
        coinbase: 'Coinbase Wallet',
        trust: 'Trust Wallet',
        phantom: 'Phantom',
        rainbow: 'Rainbow',
        zerion: 'Zerion',
        ledger: 'Ledger',
        walletconnect: 'WalletConnect',
    };

    /* ---------- DOM helpers ---------- */

    function $(id) {
        return document.getElementById(id);
    }

    function showError(msg) {
        const toast = $('wallet-error-toast');
        if (!toast) {
            if (typeof Swal !== 'undefined') Swal.fire({ icon: 'error', title: 'Wallet', text: msg });
            else alert(msg);
            return;
        }
        toast.textContent = msg;
        toast.classList.add('is-visible');
        setTimeout(function () {
            toast.classList.remove('is-visible');
        }, 4500);
    }

    function truncateAddress(addr) {
        if (!addr || addr.length < 12) return addr || '';
        return addr.slice(0, 6) + '…' + addr.slice(-4);
    }

    function updateHeaderUI() {
        document.querySelectorAll('[data-wallet-hub-trigger]').forEach(function (el) {
            if (state.connected) {
                el.classList.add('wallet-hub-connected');
                el.setAttribute('data-connected', '1');
                const label = el.querySelector('[data-wallet-label]');
                if (label) label.textContent = truncateAddress(state.address);
            } else {
                el.classList.remove('wallet-hub-connected');
                el.removeAttribute('data-connected');
                const label = el.querySelector('[data-wallet-label]');
                if (label) label.textContent = 'Connect Wallet';
            }
        });

        const bar = $('wallet-status-bar');
        if (bar) {
            if (state.connected) {
                bar.classList.add('is-visible');
                const addrEl = $('wallet-status-address');
                const chainEl = $('wallet-status-chain');
                if (addrEl) addrEl.textContent = truncateAddress(state.address);
                if (chainEl) chainEl.textContent = state.chainId ? ' · Chain ' + state.chainId : '';
            } else {
                bar.classList.remove('is-visible');
            }
        }

        document.querySelectorAll('.wallet-list-item').forEach(function (item) {
            const id = item.getAttribute('data-wallet');
            const btn = item.querySelector('.wallet-connect-btn');
            const isActive = state.connected && state.walletId === id;
            item.classList.toggle('is-connected', isActive);
            if (btn) {
                btn.textContent = isActive ? 'Connected' : 'Connect';
                btn.disabled = isActive;
            }
        });
    }

    function openModal() {
        const overlay = $('wallet-modal-overlay');
        if (overlay) overlay.classList.add('is-open');
        document.body.style.overflow = 'hidden';
        updateHeaderUI();
        startQrPairing();
    }

    function closeModal() {
        const overlay = $('wallet-modal-overlay');
        if (overlay) overlay.classList.remove('is-open');
        document.body.style.overflow = '';
    }

    /* ---------- QR (WalletConnect) ---------- */

    function setQrUi(mode, message) {
        const spinner = $('wallet-qr-spinner');
        const placeholder = $('wallet-qr-placeholder');
        const img = $('wallet-qr-img');
        const canvas = $('wallet-qr-canvas');
        const hint = $('wallet-qr-hint');

        if (spinner) spinner.classList.toggle('is-visible', mode === 'loading');
        if (placeholder) {
            placeholder.style.display = (mode === 'error' || mode === 'idle') ? 'block' : 'none';
            if (message) placeholder.textContent = message;
        }
        if (img) img.style.display = mode === 'ready' ? 'block' : 'none';
        if (canvas) canvas.style.display = 'none';
        if (hint && message && mode !== 'ready') hint.textContent = message;
        if (hint && mode === 'ready') hint.textContent = 'Scan the QR code with any mobile device wallet.';
    }

    function renderQR(uri) {
        if (!uri) return;
        lastQrUri = uri;

        const img = $('wallet-qr-img');
        const placeholder = $('wallet-qr-placeholder');
        const spinner = $('wallet-qr-spinner');
        const localBox = $('wallet-qr-code');
        if (spinner) spinner.classList.remove('is-visible');
        if (placeholder) placeholder.style.display = 'none';

        if (localBox && window.QRCode) {
            try {
                localBox.innerHTML = '';
                localBox.style.display = 'block';
                if (img) img.style.display = 'none';
                new window.QRCode(localBox, {
                    text: uri,
                    width: 196,
                    height: 196,
                    correctLevel: window.QRCode.CorrectLevel ? window.QRCode.CorrectLevel.M : 0
                });
                const hint = $('wallet-qr-hint');
                if (hint) hint.textContent = 'Scan the QR code with any mobile device wallet.';
                return;
            } catch (e) {
                console.warn('Local QR render failed, using image fallback', e);
            }
        }

        if (img) {
            img.onload = function () {
                img.style.display = 'block';
                if (localBox) localBox.style.display = 'none';
            };
            img.onerror = function () {
                img.onerror = null;
                img.src = 'https://chart.googleapis.com/chart?cht=qr&chs=220x220&chld=M|1&chl=' + encodeURIComponent(uri);
            };
            img.style.display = 'block';
            img.src = 'https://api.qrserver.com/v1/create-qr-code/?size=220x220&margin=8&ecc=M&data=' + encodeURIComponent(uri);
        }

        const hint = $('wallet-qr-hint');
        if (hint) hint.textContent = 'Scan the QR code with any mobile device wallet.';
    }

    function resetQRPanel() {
        lastQrUri = null;
        const img = $('wallet-qr-img');
        const localBox = $('wallet-qr-code');
        if (img) {
            img.removeAttribute('src');
            img.style.display = 'none';
        }
        if (localBox) {
            localBox.innerHTML = '';
            localBox.style.display = 'none';
        }
        setQrUi('idle', 'Preparing WalletConnect QR…');
    }

    function startQrPairing() {
        if (qrPairingPromise) {
            if (lastQrUri) renderQR(lastQrUri);
            return qrPairingPromise;
        }
        if (lastQrUri) {
            renderQR(lastQrUri);
            return;
        }
        if (state.connected && state.walletId === 'walletconnect') {
            setQrUi('idle', 'Wallet already connected');
            return;
        }

        setQrUi('loading', 'Generating QR code…');

        qrPairingPromise = (async function () {
            try {
                const provider = await getWalletConnectProvider();
                if (provider.connected) {
                    setQrUi('idle', 'Wallet already connected');
                    return;
                }

                bindWcUriEvents(provider);
                const existingUri = getWcUri(provider);
                if (existingUri) renderQR(existingUri);

                if (!wcConnectPromise) {
                    wcConnectPromise = startWalletConnectSession(provider).finally(function () {
                        wcConnectPromise = null;
                    });
                }

                const started = Date.now();
                while (!lastQrUri && Date.now() - started < 15000) {
                    const uri = getWcUri(provider);
                    if (uri) {
                        renderQR(uri);
                        break;
                    }
                    await new Promise(function (resolve) { setTimeout(resolve, 200); });
                }
                if (!lastQrUri) {
                    throw new Error('QR code timed out. Click WalletConnect to retry.');
                }
            } catch (err) {
                const msg = err && err.message ? err.message : String(err);
                if (/User rejected|rejected|cancelled|Modal closed/i.test(msg)) {
                    setQrUi('idle', 'QR cancelled. Click WalletConnect to try again.');
                    return;
                }
                console.error('WalletConnect QR failed', err);
                setQrUi('error', msg || 'Could not generate QR code.');
            } finally {
                qrPairingPromise = null;
            }
        })();

        return qrPairingPromise;
    }

    /* ---------- Injected provider detection ---------- */

    function getEthereumProviders() {
        const eth = window.ethereum;
        if (!eth) return [];
        if (eth.providers && Array.isArray(eth.providers)) return eth.providers;
        return [eth];
    }

    function findInjectedProvider(walletId) {
        const providers = getEthereumProviders();

        const matchers = {
            metamask: function (p) {
                return p.isMetaMask && !p.isBraveWallet && !p.isCoinbaseWallet && !p.isTrust;
            },
            coinbase: function (p) {
                return p.isCoinbaseWallet || p.isCoinbaseBrowser;
            },
            trust: function (p) {
                return p.isTrust || p.isTrustWallet;
            },
            rainbow: function (p) {
                return p.isRainbow;
            },
            zerion: function (p) {
                return p.isZerion;
            },
            phantom: function (p) {
                return window.phantom && window.phantom.ethereum;
            },
        };

        if (walletId === 'phantom') {
            return window.phantom && window.phantom.ethereum ? window.phantom.ethereum : null;
        }

        const match = matchers[walletId];
        if (!match) return null;

        for (let i = 0; i < providers.length; i++) {
            if (match(providers[i])) return providers[i];
        }

        if (providers.length === 1 && match(providers[0])) return providers[0];
        return null;
    }

    /* ---------- WalletConnect (UMD v1 — avoids broken ESM lodash imports) ---------- */

    function loadScript(src) {
        return new Promise(function (resolve, reject) {
            const existing = document.querySelector('script[src="' + src + '"]');
            if (existing) {
                if (existing.getAttribute('data-loaded') === '1' || window.WalletConnectProvider) return resolve();
                existing.addEventListener('load', resolve);
                existing.addEventListener('error', function () { reject(new Error('Failed to load WalletConnect')); });
                return;
            }
            const s = document.createElement('script');
            s.src = src;
            s.onload = function () {
                s.setAttribute('data-loaded', '1');
                resolve();
            };
            s.onerror = function () { reject(new Error('Failed to load WalletConnect')); };
            document.head.appendChild(s);
        });
    }

    function buildRpcMap() {
        const rpcMap = {};
        const chains = cfg.chains && cfg.chains.length ? cfg.chains : [1, 56, 137];
        chains.forEach(function (id) {
            if (cfg.rpc && cfg.rpc[id]) {
                rpcMap[id] = cfg.rpc[id];
            } else {
                rpcMap[id] = new URL((cfg.rpcProxyBase || 'api/rpc/proxy.php?chain=') + id, window.location.href).href;
            }
        });
        return rpcMap;
    }

    function getWcUri(provider) {
        if (!provider) return null;
        if (provider.wc && provider.wc.uri) return provider.wc.uri;
        if (provider.connector && provider.connector.uri) return provider.connector.uri;
        return lastQrUri;
    }

    function bindWcUriEvents(provider) {
        if (!provider || provider._walletHubUriBound) return;
        provider._walletHubUriBound = true;

        function onUri(err, payload) {
            let uri = null;
            if (typeof err === 'string' && err.indexOf('wc:') === 0) uri = err;
            else if (typeof payload === 'string' && payload.indexOf('wc:') === 0) uri = payload;
            else if (payload && payload.params && payload.params[0]) uri = payload.params[0];
            else if (err && err.params && err.params[0]) uri = err.params[0];
            if (uri) renderQR(uri);
        }

        if (provider.on) provider.on('display_uri', onUri);
        const connector = provider.connector || provider.wc;
        if (connector && connector.on) connector.on('display_uri', onUri);
    }

    function startWalletConnectSession(provider) {
        if (typeof provider.enable === 'function') return provider.enable();
        if (typeof provider.connect === 'function') return provider.connect();
        return Promise.reject(new Error('WalletConnect provider cannot start a session.'));
    }

    async function getWalletConnectProvider() {
        if (wcProvider) return wcProvider;
        if (wcInitPromise) return wcInitPromise;

        wcInitPromise = (async function () {
            if (!window.WalletConnectProvider) {
                await loadScript('https://unpkg.com/@walletconnect/web3-provider@1.7.8/dist/umd/index.min.js');
            }
            const WC = window.WalletConnectProvider && (window.WalletConnectProvider.default || window.WalletConnectProvider);
            if (!WC) {
                throw new Error('WalletConnect library failed to load. Refresh and try again.');
            }

            wcProvider = new WC({
                rpc: buildRpcMap(),
                chainId: (cfg.chains && cfg.chains[0]) ? cfg.chains[0] : 1,
                qrcode: false
            });

            bindWcUriEvents(wcProvider);
            if (wcProvider.on) {
                wcProvider.on('disconnect', function () {
                    handleDisconnect();
                });
            }

            return wcProvider;
        })().catch(function (err) {
            wcInitPromise = null;
            throw err;
        });

        return wcInitPromise;
    }

    async function connectWalletConnect(walletId, silent) {
        if (!silent) openModal();
        const provider = await getWalletConnectProvider();
        bindWcUriEvents(provider);
        if (!provider.connected) {
            if (!qrPairingPromise && !lastQrUri) {
                setQrUi('loading', 'Generating QR code…');
            }
            if (!wcConnectPromise) {
                wcConnectPromise = startWalletConnectSession(provider).finally(function () {
                    wcConnectPromise = null;
                });
            }
            await wcConnectPromise;
        }
        return finalizeConnection(provider, walletId || 'walletconnect', silent);
    }

    /* ---------- Session persistence ---------- */

    function saveLocalSession() {
        try {
            localStorage.setItem(
                STORAGE_KEY,
                JSON.stringify({
                    walletId: state.walletId,
                    address: state.address,
                    chainId: state.chainId,
                })
            );
        } catch (e) {
            /* ignore quota errors */
        }
    }

    function clearLocalSession() {
        try {
            localStorage.removeItem(STORAGE_KEY);
        } catch (e) {
            /* ignore */
        }
    }

    async function saveServerSession(provider, address, chainId) {
        if (!cfg.api || !cfg.api.saveSession) return;
        try {
            const res = await fetch(cfg.api.saveSession, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                credentials: 'same-origin',
                body: JSON.stringify({
                    provider: provider,
                    address: address,
                    chain_id: chainId,
                    session: { walletId: state.walletId, type: 'auto' },
                }),
            });
            const data = await res.json();
            if (!data.ok) console.warn('Server session save failed', data);
        } catch (e) {
            console.warn('Server session save error', e);
        }
    }

    async function clearServerSession() {
        if (!cfg.api || !cfg.api.disconnect) return;
        try {
            await fetch(cfg.api.disconnect, { method: 'POST', credentials: 'same-origin' });
        } catch (e) {
            console.warn('Server disconnect error', e);
        }
    }

    /* ---------- Connection lifecycle ---------- */

    function bindProviderEvents(provider) {
        if (!provider || !provider.on) return;
        provider.removeListener && provider.removeListener('accountsChanged', handleAccountsChanged);
        provider.removeListener && provider.removeListener('chainChanged', handleChainChanged);
        provider.on('accountsChanged', handleAccountsChanged);
        provider.on('chainChanged', handleChainChanged);
    }

    async function handleAccountsChanged(accounts) {
        if (!accounts || !accounts.length) {
            await disconnect(true);
            return;
        }
        state.address = accounts[0];
        saveLocalSession();
        await saveServerSession(state.providerLabel, state.address, state.chainId);
        updateHeaderUI();
        document.dispatchEvent(new CustomEvent('walletHub:accountsChanged', { detail: { address: state.address } }));
    }

    function handleChainChanged(chainId) {
        const id = typeof chainId === 'string' ? parseInt(chainId, 16) : chainId;
        state.chainId = id;
        saveLocalSession();
        updateHeaderUI();
        document.dispatchEvent(new CustomEvent('walletHub:chainChanged', { detail: { chainId: id } }));
    }

    async function handleDisconnect() {
        await disconnect(true);
    }

    async function finalizeConnection(provider, walletId, silent) {
        if (typeof ethers === 'undefined') {
            throw new Error('Ethers.js is not loaded.');
        }

        activeProvider = provider;
        ethersProvider = new ethers.providers.Web3Provider(provider);
        const signer = ethersProvider.getSigner();
        const address = await signer.getAddress();
        const network = await ethersProvider.getNetwork();

        state.connected = true;
        state.address = address;
        state.chainId = network.chainId;
        state.walletId = walletId;
        state.providerLabel = walletId;

        bindProviderEvents(provider);
        saveLocalSession();
        await saveServerSession(walletId, address, network.chainId);
        updateHeaderUI();

        if (!silent) closeModal();

        document.dispatchEvent(
            new CustomEvent('walletHub:connected', {
                detail: { address: address, chainId: network.chainId, walletId: walletId },
            })
        );

        return { address: address, chainId: network.chainId };
    }

    async function connectInjected(walletId, silent) {
        let provider = findInjectedProvider(walletId);

        if (!provider && walletId === 'metamask' && window.ethereum) {
            provider = window.ethereum;
        }

        if (!provider) {
            if (walletId === 'ledger' || walletId === 'zerion' || walletId === 'trust') {
                return connectWalletConnect(walletId, silent);
            }
            const name = WALLET_LABELS[walletId] || walletId;
            throw new Error(name + ' not detected in this browser. Install the extension or use WalletConnect (QR).');
        }

        await provider.request({ method: 'eth_requestAccounts' });
        return finalizeConnection(provider, walletId, silent);
    }

    async function connect(walletId, options) {
        const silent = options && options.silent;
        const id = walletId || 'walletconnect';

        const item = document.querySelector('.wallet-list-item[data-wallet="' + id + '"]');
        const btn = item && item.querySelector('.wallet-connect-btn');
        if (btn) {
            btn.classList.add('is-loading');
            btn.textContent = 'Connecting…';
        }

        try {
            if (id === 'walletconnect' || id === 'ledger') {
                return await connectWalletConnect(id, silent);
            }
            return await connectInjected(id, silent);
        } finally {
            if (btn) {
                btn.classList.remove('is-loading');
                updateHeaderUI();
            }
        }
    }

    async function disconnect(silent) {
        if (wcProvider) {
            try {
                if (typeof wcProvider.disconnect === 'function') await wcProvider.disconnect();
                else if (typeof wcProvider.close === 'function') await wcProvider.close();
            } catch (e) {
                /* ignore */
            }
        }
        wcProvider = null;
        wcInitPromise = null;
        qrPairingPromise = null;
        wcConnectPromise = null;
        lastQrUri = null;
        activeProvider = null;
        ethersProvider = null;

        state.connected = false;
        state.address = null;
        state.chainId = null;
        state.walletId = null;
        state.providerLabel = null;

        clearLocalSession();
        if (!silent) await clearServerSession();
        resetQRPanel();
        updateHeaderUI();

        document.dispatchEvent(new CustomEvent('walletHub:disconnected'));
    }

    async function autoReconnect() {
        let local = null;
        try {
            const raw = localStorage.getItem(STORAGE_KEY);
            if (raw) local = JSON.parse(raw);
        } catch (e) {
            return;
        }

        if (!local || !local.walletId) return;

        try {
            if (local.walletId === 'walletconnect' || local.walletId === 'ledger') {
                await connectWalletConnect(local.walletId, true);
            } else {
                const provider = findInjectedProvider(local.walletId) || window.ethereum;
                if (!provider) return;
                const accounts = await provider.request({ method: 'eth_accounts' });
                if (accounts && accounts.length) {
                    await finalizeConnection(provider, local.walletId, true);
                }
            }
        } catch (e) {
            console.warn('Wallet auto-reconnect skipped:', e.message);
        }
    }

    async function ensureConnected() {
        if (state.connected && ethersProvider) {
            return { address: state.address, chainId: state.chainId, signer: ethersProvider.getSigner() };
        }
        await autoReconnect();
        if (state.connected && ethersProvider) {
            return { address: state.address, chainId: state.chainId, signer: ethersProvider.getSigner() };
        }
        openModal();
        throw new Error('Wallet not connected');
    }

    async function getSigner() {
        const session = await ensureConnected();
        return session.signer;
    }

    function bindModalEvents() {
        const overlay = $('wallet-modal-overlay');
        const closeBtn = $('wallet-modal-close');
        const showWc = $('wallet-show-wc');

        if (closeBtn) closeBtn.addEventListener('click', closeModal);
        if (overlay) {
            overlay.addEventListener('click', function (e) {
                if (e.target === overlay) closeModal();
            });
        }

        document.querySelectorAll('.wallet-list-item .wallet-connect-btn').forEach(function (btn) {
            btn.addEventListener('click', function (e) {
                e.stopPropagation();
                const item = btn.closest('.wallet-list-item');
                const walletId = item && item.getAttribute('data-wallet');
                if (walletId) connect(walletId).catch(function (err) {
                    showError(err && err.message ? err.message : String(err));
                });
            });
        });

        if (showWc) {
            showWc.addEventListener('click', function (e) {
                e.preventDefault();
                connect('walletconnect').catch(function (err) {
                    showError(err && err.message ? err.message : String(err));
                });
            });
        }

        document.querySelectorAll('[data-wallet-hub-trigger]').forEach(function (el) {
            el.addEventListener('click', function (e) {
                e.preventDefault();
                if (state.connected && el.getAttribute('data-wallet-disconnect-on-connected') === '1') {
                    disconnect();
                    return;
                }
                const preset = el.getAttribute('data-wallet-hub-preset');
                if (preset === 'browser') {
                    const tryOrder = ['metamask', 'coinbase', 'trust', 'phantom', 'rainbow'];
                    (async function () {
                        for (let i = 0; i < tryOrder.length; i++) {
                            const p = findInjectedProvider(tryOrder[i]);
                            if (p) {
                                try {
                                    await connect(tryOrder[i]);
                                    return;
                                } catch (err) {
                                    /* try next */
                                }
                            }
                        }
                        if (window.ethereum) {
                            try {
                                await connect('metamask');
                                return;
                            } catch (err) {
                                /* fall through to modal */
                            }
                        }
                        openModal();
                    })().catch(function (err) {
                        showError(err && err.message ? err.message : String(err));
                    });
                    return;
                }
                openModal();
            });
        });

        document.querySelectorAll('.wallet-icon').forEach(function (img) {
            img.addEventListener('error', function () {
                if (img.dataset.fallbackApplied) return;
                img.dataset.fallbackApplied = '1';
                const name = (img.alt || '?').charAt(0).toUpperCase();
                const badge = document.createElement('div');
                badge.className = 'wallet-icon-fallback';
                badge.style.background = '#334155';
                badge.textContent = name;
                img.replaceWith(badge);
            });
        });

        document.addEventListener('keydown', function (e) {
            if (e.key === 'Escape') closeModal();
        });
    }

    async function init() {
        bindModalEvents();
        await autoReconnect();
        updateHeaderUI();
    }

    window.WalletHub = {
        openModal: openModal,
        closeModal: closeModal,
        connect: connect,
        disconnect: disconnect,
        isConnected: function () {
            return state.connected;
        },
        getAddress: function () {
            return state.address;
        },
        getChainId: function () {
            return state.chainId;
        },
        getProvider: function () {
            return activeProvider;
        },
        getEthersProvider: function () {
            return ethersProvider;
        },
        getSigner: getSigner,
        ensureConnected: ensureConnected,
        init: init,
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
