import { ref, computed } from 'vue'
import EthereumProvider from '@walletconnect/ethereum-provider'
import {
  encodeFunctionData,
  erc20Abi,
  getAddress,
  parseEther,
  parseUnits,
  toHex,
} from 'viem'
import {
  chainIdHex,
  erc20DecimalsForChain,
  resolveEvmChainId,
} from '@/utils/evmRecharge'
import type { RechargeFlatNetworkOption, RechargeOrderDetail } from '@/stores/deposit'

/** 公共 RPC（仅用于 wallet_addEthereumChain；实际交易由钱包自选节点） */
const RPC_FALLBACK: Record<number, string> = {
  1: 'https://eth.llamarpc.com',
  56: 'https://bsc-dataseed.binance.org',
  137: 'https://polygon-rpc.com',
  42161: 'https://arb1.arbitrum.io/rpc',
  8453: 'https://mainnet.base.org',
  10: 'https://mainnet.optimism.io',
}

const CHAIN_META: Record<
  number,
  { chainName: string; nativeCurrency: { name: string; symbol: string; decimals: number } }
> = {
  1: { chainName: 'Ethereum Mainnet', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 } },
  56: { chainName: 'BNB Smart Chain', nativeCurrency: { name: 'BNB', symbol: 'BNB', decimals: 18 } },
  137: { chainName: 'Polygon Mainnet', nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 } },
  42161: { chainName: 'Arbitrum One', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 } },
  8453: { chainName: 'Base', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 } },
  10: { chainName: 'Optimism', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 } },
}

let providerInit: Promise<InstanceType<typeof EthereumProvider>> | null = null
type EvmProvider = InstanceType<typeof EthereumProvider>

const WALLET_CONNECT_TIMEOUT_MS = 45_000

function getProjectId(): string {
  return String(import.meta.env.VITE_WALLETCONNECT_PROJECT_ID ?? '').trim()
}

function parseWalletAccount(accounts: string[]): string {
  const raw = accounts[0]
  if (!raw) {
    throw new Error('未获取到钱包地址')
  }
  if (raw.includes(':')) {
    const parts = raw.split(':')
    return getAddress(parts[parts.length - 1] as `0x${string}`)
  }
  return getAddress(raw as `0x${string}`)
}

function hasEip155Session(provider: EvmProvider): boolean {
  return Boolean(provider.session?.namespaces?.eip155?.accounts?.length)
}

async function getProvider() {
  const projectId = getProjectId()
  if (!projectId) {
    throw new Error('未配置 VITE_WALLETCONNECT_PROJECT_ID')
  }
  if (!providerInit) {
    const optionalChains = [56, 137, 42161, 8453, 10]
    const rpcMap: Record<number, string> = {}
    for (const id of [1, ...optionalChains]) {
      const u = RPC_FALLBACK[id]
      if (u) {
        rpcMap[id] = u
      }
    }
    providerInit = EthereumProvider.init({
      projectId,
      chains: [1],
      optionalChains,
      showQrModal: true,
      rpcMap,
      metadata: {
        name: 'iBit',
        description: '链上充值',
        url: typeof window !== 'undefined' ? window.location.origin : 'https://ibit.com',
        icons: [],
      },
    })
  }
  return providerInit
}

async function resetWalletConnectProvider() {
  const pendingProvider = providerInit
  providerInit = null
  if (!pendingProvider) {
    return
  }
  try {
    const provider = await pendingProvider
    provider.modal?.closeModal?.()
    if (provider.session || provider.connected || provider.connecting) {
      await provider.disconnect()
    }
  } catch {
    // Reset is best-effort; the next click will create a fresh provider.
  }
}

function withTimeout<T>(promise: Promise<T>, message: string): Promise<T> {
  let timer: number | undefined
  const timeout = new Promise<never>((_, reject) => {
    timer = window.setTimeout(() => {
      reject(new Error(message))
    }, WALLET_CONNECT_TIMEOUT_MS)
  })
  return Promise.race([promise, timeout]).finally(() => {
    if (timer) {
      window.clearTimeout(timer)
    }
  })
}

async function ensureEvmConnected(provider: EvmProvider, chainId: number) {
  if (provider.session && !hasEip155Session(provider)) {
    await provider.disconnect()
  }
  if (!provider.session || !provider.connected || !hasEip155Session(provider) || provider.accounts.length === 0) {
    await withTimeout(provider.connect({ chains: [chainId] }), '钱包连接超时，请重新点击连接钱包')
  }
  if (provider.accounts.length === 0) {
    await withTimeout(provider.enable(), '钱包授权超时，请重新点击连接钱包')
  }
  if (provider.accounts.length === 0) {
    throw new Error('未获取到钱包地址')
  }
}

async function ensureChain(provider: EvmProvider, chainId: number) {
  const hex = chainIdHex(chainId)
  try {
    await provider.request({
      method: 'wallet_switchEthereumChain',
      params: [{ chainId: hex }],
    })
  } catch (e: unknown) {
    const err = e as { code?: number }
    if (err?.code === 4902) {
      const meta = CHAIN_META[chainId]
      const rpcUrl = RPC_FALLBACK[chainId]
      if (!meta || !rpcUrl) {
        throw new Error(`不支持自动添加链 chainId=${chainId}，请在钱包中手动切换网络`)
      }
      await provider.request({
        method: 'wallet_addEthereumChain',
        params: [
          {
            chainId: hex,
            chainName: meta.chainName,
            nativeCurrency: meta.nativeCurrency,
            rpcUrls: [rpcUrl],
            blockExplorerUrls: [],
          },
        ],
      })
    } else {
      throw e
    }
  }
}

export function useWalletConnectDeposit() {
  const wcBusy = ref(false)
  const wcConfigured = computed(() => !!getProjectId())

  function resetWalletBusy() {
    wcBusy.value = false
    void resetWalletConnectProvider()
  }

  function canPayWithWallet(
    network: RechargeFlatNetworkOption | null,
    order: RechargeOrderDetail | null,
  ): boolean {
    if (!network || !order || Number(order.status) !== 0) {
      return false
    }
    return resolveEvmChainId(network.protocol, network.networkName) !== null
  }

  /**
   * 连接 WalletConnect 并在当前 EVM 链上发起 USDT/代币 transfer（或主币转账）。
   * @returns 交易 hash（0x…）
   */
  async function connectAndPay(params: {
    network: RechargeFlatNetworkOption
    order: RechargeOrderDetail
  }): Promise<string> {
    const { network, order } = params
    const chainId = resolveEvmChainId(network.protocol, network.networkName)
    if (chainId == null) {
      throw new Error('当前网络不支持 WalletConnect，请使用对应链钱包手动转账')
    }
    wcBusy.value = true
    try {
      let provider = await getProvider()
      if (provider.connecting && !provider.session) {
        await resetWalletConnectProvider()
        provider = await getProvider()
      }
      await ensureEvmConnected(provider, chainId)
      await ensureChain(provider, chainId)

      const accounts = provider.accounts
      const from = parseWalletAccount(accounts)
      const to = getAddress(order.rechargeAddress as `0x${string}`)
      const amountStr = String(order.amount).trim()
      const contractAddr = network.contractAddress?.trim()

      if (contractAddr) {
        const token = getAddress(contractAddr as `0x${string}`)
        const decimals = erc20DecimalsForChain(chainId)
        const amountWei = parseUnits(amountStr, decimals)
        const data = encodeFunctionData({
          abi: erc20Abi,
          functionName: 'transfer',
          args: [to, amountWei],
        })
        const hash = await provider.request<`0x${string}`>({
          method: 'eth_sendTransaction',
          params: [
            {
              from,
              to: token,
              data,
            },
          ],
        })
        return hash
      } else {
        const valueWei = parseEther(amountStr)
        const hash = await provider.request<`0x${string}`>({
          method: 'eth_sendTransaction',
          params: [
            {
              from,
              to,
              value: toHex(valueWei),
            },
          ],
        })
        return hash
      }
    } finally {
      wcBusy.value = false
    }
  }

  return {
    wcBusy,
    wcConfigured,
    resetWalletBusy,
    canPayWithWallet,
    connectAndPay,
  }
}
