import { createWalletClient, custom } from 'viem';
/**
 * Default adapter for injected wallets (MetaMask, Rabby, etc.) using EIP-1193.
 */
export class Eip1193WalletAdapter {
    id = 'eip1193';
    configProvider;
    enforceChainId;
    autoSwitchChain;
    chainConfig;
    /** Provider resolved after connect, used for event subscriptions. */
    resolvedProvider = null;
    /** Bound handlers tracked for cleanup on disconnect. */
    boundHandlers = [];
    constructor(config) {
        this.configProvider = config?.provider;
        this.enforceChainId = config?.enforceChainId ?? false;
        this.autoSwitchChain = config?.autoSwitchChain ?? true;
        this.chainConfig = config?.chainConfig;
    }
    getProvider() {
        return this.configProvider ?? (typeof window !== 'undefined' ? window.ethereum : undefined);
    }
    async switchChain(provider, chainId, rpcUrl) {
        const chainIdHex = `0x${chainId.toString(16)}`;
        try {
            await provider.request({
                method: 'wallet_switchEthereumChain',
                params: [{ chainId: chainIdHex }],
            });
        }
        catch (switchError) {
            const err = switchError;
            if (err.code === 4902) {
                const chainName = this.chainConfig?.chainName || `Chain ${chainId}`;
                const nativeCurrency = this.chainConfig?.nativeCurrency || {
                    name: 'ETH',
                    symbol: 'ETH',
                    decimals: 18,
                };
                const rpcUrls = this.chainConfig?.rpcUrls || [rpcUrl || 'https://rpc.unavailable'];
                const blockExplorerUrls = this.chainConfig?.blockExplorerUrls;
                try {
                    await provider.request({
                        method: 'wallet_addEthereumChain',
                        params: [
                            {
                                chainId: chainIdHex,
                                chainName,
                                nativeCurrency,
                                rpcUrls,
                                ...(blockExplorerUrls ? { blockExplorerUrls } : {}),
                            },
                        ],
                    });
                }
                catch (addError) {
                    const addErr = addError;
                    if (addErr.code === 4001) {
                        throw new Error(`User rejected adding ${chainName} network to wallet`);
                    }
                    throw addError;
                }
            }
            else if (err.code === 4001) {
                const chainName = this.chainConfig?.chainName || `chain ${chainId}`;
                throw new Error(`User rejected switching to ${chainName} network`);
            }
            else {
                throw switchError;
            }
        }
    }
    async connect(args) {
        const provider = this.getProvider();
        if (!provider)
            throw new Error('No Ethereum provider found');
        const accounts = (await provider.request({
            method: 'eth_requestAccounts',
        }));
        if (!accounts || accounts.length === 0) {
            throw new Error('No accounts available');
        }
        const account = accounts[0];
        let chainIdHex = (await provider.request({ method: 'eth_chainId' }));
        let chainId = parseInt(chainIdHex, 16);
        if (args.expectedChainId && chainId !== args.expectedChainId) {
            if (this.autoSwitchChain) {
                await this.switchChain(provider, args.expectedChainId, args.rpcUrl);
                chainIdHex = (await provider.request({ method: 'eth_chainId' }));
                chainId = parseInt(chainIdHex, 16);
            }
            else if (this.enforceChainId) {
                throw new Error(`Wrong network: expected chainId=${args.expectedChainId}, got chainId=${chainId}`);
            }
        }
        const chain = {
            id: chainId,
            name: 'Network',
            nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
            rpcUrls: {
                default: { http: [args.rpcUrl || 'https://rpc.unavailable'] },
                public: { http: [args.rpcUrl || 'https://rpc.unavailable'] },
            },
            blockTime: 1,
        };
        const walletClient = createWalletClient({
            account: account,
            chain,
            transport: custom(provider),
        });
        this.resolvedProvider = provider;
        return { walletClient, address: account, chainId };
    }
    async tryReconnect(args) {
        const provider = this.getProvider();
        if (!provider)
            return null;
        const accounts = (await provider.request({ method: 'eth_accounts' }));
        if (!accounts || accounts.length === 0)
            return null;
        const account = accounts[0];
        const chainIdHex = (await provider.request({ method: 'eth_chainId' }));
        const chainId = parseInt(chainIdHex, 16);
        if (this.enforceChainId && args.expectedChainId && chainId !== args.expectedChainId) {
            return null;
        }
        const chain = {
            id: chainId,
            name: 'Network',
            nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
            rpcUrls: {
                default: { http: [args.rpcUrl || 'https://rpc.unavailable'] },
                public: { http: [args.rpcUrl || 'https://rpc.unavailable'] },
            },
            blockTime: 1,
        };
        const walletClient = createWalletClient({
            account: account,
            chain,
            transport: custom(provider),
        });
        this.resolvedProvider = provider;
        return { walletClient, address: account, chainId };
    }
    onAccountsChanged(handler) {
        const provider = this.resolvedProvider;
        if (!provider?.on || !provider?.removeListener) {
            return () => { };
        }
        const wrappedHandler = (...args) => {
            handler(args[0]);
        };
        provider.on('accountsChanged', wrappedHandler);
        this.boundHandlers.push({ event: 'accountsChanged', handler: wrappedHandler });
        return () => {
            provider.removeListener('accountsChanged', wrappedHandler);
            this.boundHandlers = this.boundHandlers.filter((h) => h.handler !== wrappedHandler);
        };
    }
    onChainChanged(handler) {
        const provider = this.resolvedProvider;
        if (!provider?.on || !provider?.removeListener) {
            return () => { };
        }
        const wrappedHandler = (...args) => {
            const raw = args[0];
            const parsed = parseInt(raw, 16);
            if (!Number.isNaN(parsed))
                handler(parsed);
        };
        provider.on('chainChanged', wrappedHandler);
        this.boundHandlers.push({ event: 'chainChanged', handler: wrappedHandler });
        return () => {
            provider.removeListener('chainChanged', wrappedHandler);
            this.boundHandlers = this.boundHandlers.filter((h) => h.handler !== wrappedHandler);
        };
    }
    disconnect() {
        const provider = this.resolvedProvider;
        if (provider?.removeListener) {
            for (const { event, handler } of this.boundHandlers) {
                provider.removeListener(event, handler);
            }
        }
        this.boundHandlers = [];
        this.resolvedProvider = null;
    }
}
//# sourceMappingURL=Eip1193WalletAdapter.js.map