import _objectSpread from '@babel/runtime/helpers/objectSpread2';
import { hydrate } from '@wagmi/core';
import { useConfig, useReconnect, useAccountEffect, configKey, createConfig } from '@wagmi/vue';
import { injected } from '@wagmi/vue/connectors';
import { randomId } from '@web3auth/auth';
import { log, CHAIN_NAMESPACES, WalletInitializationError } from '@web3auth/no-modal';
import { defineChain, webSocket, http, fallback } from 'viem';
import { defineComponent, h, watch, provide, shallowRef, ref } from 'vue';
import '@web3auth/no-modal/vue';
import { useWeb3Auth } from '../composables/useWeb3Auth.js';
import { useWeb3AuthDisconnect } from '../composables/useWeb3AuthDisconnect.js';
import { defaultWagmiConfig } from './constants.js';

const WEB3AUTH_CONNECTOR_ID = "web3auth";

// Helper to initialize connectors for the given wallets
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function setupConnector(provider, config) {
  let connector = config.connectors.find(c => c.id === WEB3AUTH_CONNECTOR_ID);
  if (connector) return connector;

  // Create new connector if not already existing
  connector = injected({
    target: {
      provider: provider,
      id: WEB3AUTH_CONNECTOR_ID,
      name: "Web3Auth"
    }
  });
  const result = config._internal.connectors.setup(connector);
  config._internal.connectors.setState(current => [...current, result]);
  return result;
}

// Helper to connect a wallet and update wagmi state
async function connectWeb3AuthWithWagmi(connector, config) {
  var _config$storage, _config$storage2;
  await Promise.all([(_config$storage = config.storage) === null || _config$storage === void 0 ? void 0 : _config$storage.removeItem(`${connector.id}.disconnected`), (_config$storage2 = config.storage) === null || _config$storage2 === void 0 ? void 0 : _config$storage2.setItem("recentConnectorId", connector.id)]);
  let chainId = await connector.getChainId();
  if (!config.chains.find(c => c.id === chainId)) {
    chainId = config.chains[0].id;
  }
  const accounts = await connector.getAccounts();
  const connections = new Map([[connector.uid, {
    accounts: [accounts[0]],
    chainId,
    connector
  }]]);
  config.setState(state => _objectSpread(_objectSpread({}, state), {}, {
    chainId,
    connections,
    current: connector.uid,
    status: "connected"
  }));
}
async function disconnectWeb3AuthFromWagmi(config) {
  config._internal.connectors.setState(prev => prev.filter(c => c.id !== WEB3AUTH_CONNECTOR_ID));
  config.setState(state => _objectSpread(_objectSpread({}, state), {}, {
    chainId: state.chainId,
    connections: new Map(),
    current: undefined,
    status: "disconnected"
  }));
}
const Web3AuthWagmiProvider = defineComponent({
  name: "Web3AuthWagmiProvider",
  setup() {
    const {
      isConnected,
      provider
    } = useWeb3Auth();
    const {
      disconnect
    } = useWeb3AuthDisconnect();
    const wagmiConfig = useConfig();
    const {
      reconnect
    } = useReconnect();
    useAccountEffect({
      onDisconnect: async () => {
        log.info("Disconnected from wagmi");
        if (isConnected.value) await disconnect();
      }
    });
    watch(isConnected, async newIsConnected => {
      if (newIsConnected && provider.value) {
        const connector = await setupConnector(provider.value, wagmiConfig);
        if (!connector) {
          log.error("Failed to setup vue wagmi connector");
          throw new Error("Failed to setup connector");
        }
        await connectWeb3AuthWithWagmi(connector, wagmiConfig);
        reconnect();
      } else if (!newIsConnected) {
        if (wagmiConfig.state.status === "connected") {
          await disconnectWeb3AuthFromWagmi(wagmiConfig);
        }
      }
    }, {
      immediate: true
    });
  },
  render() {
    var _this$$slots$default;
    return h((_this$$slots$default = this.$slots.default) !== null && _this$$slots$default !== void 0 ? _this$$slots$default : "");
  }
});
const Web3AuthWagmiInnerProvider = defineComponent({
  name: "Web3AuthWagmiInnerProvider",
  props: {
    config: {
      type: Object,
      required: false
    }
  },
  setup(props) {
    const {
      config
    } = props;
    provide(configKey, config);
  },
  render() {
    var _this$$slots$default2;
    return h(Web3AuthWagmiProvider, {}, (_this$$slots$default2 = this.$slots.default) !== null && _this$$slots$default2 !== void 0 ? _this$$slots$default2 : "");
  }
});
const WagmiProvider = defineComponent({
  name: "WagmiProvider",
  props: {
    config: {
      type: Object,
      required: false
    }
  },
  setup(props) {
    const {
      config
    } = props;
    const {
      web3Auth,
      isInitialized
    } = useWeb3Auth();
    const finalConfig = shallowRef(defaultWagmiConfig);
    const configKey = ref(randomId());
    const getTransport = chain => {
      const {
        wsTarget,
        rpcTarget,
        fallbackWsTargets = [],
        fallbackRpcTargets = []
      } = chain;
      const transports = [];
      if (wsTarget) transports.push(webSocket(wsTarget));
      if (fallbackWsTargets.length > 0) transports.push(...fallbackWsTargets.map(target => webSocket(target)));
      if (rpcTarget) transports.push(http(rpcTarget));
      if (fallbackRpcTargets.length > 0) transports.push(...fallbackRpcTargets.map(target => http(target)));
      return fallback(transports);
    };
    const defineWagmiConfig = () => {
      var _web3Auth$value;
      const configParams = _objectSpread(_objectSpread({
        ssr: true
      }, config), {}, {
        chains: undefined,
        connectors: [],
        transports: {},
        multiInjectedProviderDiscovery: false,
        client: undefined
      });
      const wagmiChains = [];
      if (isInitialized.value && web3Auth !== null && web3Auth !== void 0 && (_web3Auth$value = web3Auth.value) !== null && _web3Auth$value !== void 0 && (_web3Auth$value = _web3Auth$value.coreOptions) !== null && _web3Auth$value !== void 0 && _web3Auth$value.chains) {
        var _web3Auth$value$curre;
        const defaultChainId = (_web3Auth$value$curre = web3Auth.value.currentChain) === null || _web3Auth$value$curre === void 0 ? void 0 : _web3Auth$value$curre.chainId;
        const chains = web3Auth.value.coreOptions.chains.filter(chain => chain.chainNamespace === CHAIN_NAMESPACES.EIP155);
        if (chains.length === 0) throw WalletInitializationError.invalidParams("No valid chains found in web3auth config for wagmi.");
        chains.forEach(chain => {
          const wagmiChain = defineChain({
            id: Number.parseInt(chain.chainId, 16),
            // id in number form
            name: chain.displayName,
            rpcUrls: {
              default: {
                http: [chain.rpcTarget],
                webSocket: [chain.wsTarget]
              }
            },
            blockExplorers: chain.blockExplorerUrl ? {
              default: {
                name: "explorer",
                // TODO: correct name if chain config has it
                url: chain.blockExplorerUrl
              }
            } : undefined,
            nativeCurrency: {
              name: chain.tickerName,
              symbol: chain.ticker,
              decimals: chain.decimals || 18
            }
          });
          if (defaultChainId === chain.chainId) {
            wagmiChains.unshift(wagmiChain);
          } else {
            wagmiChains.push(wagmiChain);
          }
          configParams.transports[wagmiChain.id] = getTransport(chain);
        });
        configParams.chains = [wagmiChains[0], ...wagmiChains.slice(1)];
      }
      return createConfig(configParams);
    };
    const hydrateWagmiConfig = () => {
      if (finalConfig.value) {
        hydrate(finalConfig.value, _objectSpread({
          reconnectOnMount: false
        }, props.config));
      }
    };
    watch(isInitialized, (newIsInitialized, prevIsInitialized) => {
      var _web3Auth$value2;
      (_web3Auth$value2 = web3Auth.value) === null || _web3Auth$value2 === void 0 || _web3Auth$value2.setAnalyticsProperties({
        wagmi_enabled: true
      });
      if (newIsInitialized && !prevIsInitialized) {
        finalConfig.value = defineWagmiConfig();
        hydrateWagmiConfig();
        configKey.value = randomId();
      }
    }, {
      immediate: true
    });
    if (!isInitialized.value) {
      hydrateWagmiConfig();
    }
    return {
      finalConfig,
      configKey
    };
  },
  render() {
    return h(Web3AuthWagmiInnerProvider, {
      config: this.finalConfig,
      key: this.configKey
    }, {
      default: () => {
        var _this$$slots$default3, _this$$slots;
        return (_this$$slots$default3 = (_this$$slots = this.$slots).default) === null || _this$$slots$default3 === void 0 ? void 0 : _this$$slots$default3.call(_this$$slots);
      }
    });
  }
});

export { WagmiProvider };
