'use client'

import { useEffect, useMemo, useState } from 'react'
import type { WalletChain } from '@/components/wallet/AddToMetaMask'
import { getActiveWalletConnectProvider } from '@/services/wallet/walletConnectClient'
import { toWalletAddEthereumChainParams } from '@/utils/walletAddEthereumChain'
import {
  isMobileWalletContext,
  MOBILE_WALLET_BUTTON_CLASS,
  resolveWalletEthereumProvider,
} from '@/utils/walletProviderEnv'
import { isWalletWatchEligibleAddress } from '@/utils/walletWatchEligible'
import { watchTokenInWallet } from '@/utils/walletWatchToken'

const FALLBACK_CHAIN_138: WalletChain = {
  chainId: '0x8a',
  chainIdDecimal: 138,
  chainName: 'DeFi Oracle Meta Mainnet',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: ['https://rpc-http-pub.d-bis.org'],
  blockExplorerUrls: ['https://explorer.d-bis.org', 'https://blockscout.defi-oracle.io'],
  iconUrls: [
    'https://explorer.d-bis.org/api/v1/report/logo/chain-138',
    'https://explorer.d-bis.org/token-icons/chain-138.png',
    'https://explorer.d-bis.org/favicon.ico',
  ],
}

type AddTokenToWalletButtonProps = {
  address: string
  symbol: string
  decimals: number
  name?: string
  logoURI?: string
  chainId?: number
  variant?: 'primary' | 'secondary'
  className?: string
}

export default function AddTokenToWalletButton({
  address,
  symbol,
  decimals,
  name,
  logoURI,
  chainId = 138,
  variant = 'primary',
  className = '',
}: AddTokenToWalletButtonProps) {
  const [status, setStatus] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [chainNetwork, setChainNetwork] = useState<WalletChain | null>(null)
  const [providerTick, setProviderTick] = useState(0)

  useEffect(() => {
    if (typeof window === 'undefined') return undefined
    const refresh = () => setProviderTick((value) => value + 1)
    window.addEventListener('ethereum#initialized', refresh)
    window.addEventListener('focus', refresh)
    return () => {
      window.removeEventListener('ethereum#initialized', refresh)
      window.removeEventListener('focus', refresh)
    }
  }, [])

  useEffect(() => {
    let active = true
    const apiBase = window.location.origin.replace(/\/+$/, '')
    void fetch(`${apiBase}/api/v1/config/metamask?chainId=${chainId}`, { cache: 'no-store' })
      .then((res) => (res.ok ? res.json() : null))
      .then((payload) => {
        if (!active) return
        if (payload?.addEthereumChain) {
          setChainNetwork(payload.addEthereumChain as WalletChain)
        }
      })
      .catch(() => {
        if (active) setChainNetwork(null)
      })
    return () => {
      active = false
    }
  }, [chainId])

  const network = useMemo(() => {
    if (chainId === 138) return chainNetwork || FALLBACK_CHAIN_138
    return chainNetwork
  }, [chainId, chainNetwork])

  const resolveEthereum = () => {
    void providerTick
    return resolveWalletEthereumProvider(getActiveWalletConnectProvider())
  }

  const addChainOnly = async () => {
    setError(null)
    setStatus(null)
    if (!network) {
      setError('Network metadata is unavailable right now.')
      return
    }
    const ethereum = resolveEthereum()
    if (!ethereum) {
      setError('No wallet provider found. Connect MetaMask, open this page in a wallet browser, or use WalletConnect on /wallet.')
      return
    }
    try {
      await ethereum.request({
        method: 'wallet_addEthereumChain',
        params: [
          toWalletAddEthereumChainParams(network, {
            preferSingleRpc: isMobileWalletContext(),
          }),
        ],
      })
      setStatus(`Added ${network.chainName}.`)
    } catch (e) {
      const err = e as { code?: number; message?: string }
      if (err.code === 4902) {
        setStatus(`Added ${network.chainName}.`)
        return
      }
      setError(err.message || `Failed to add ${network.chainName}.`)
    }
  }

  const addToken = async () => {
    setError(null)
    setStatus(null)

    if (!isWalletWatchEligibleAddress(address)) {
      setError(`${symbol} uses a roadmap placeholder address on Chain 138. Use a live canonical token from the token index instead.`)
      return
    }

    if (!network) {
      setError('Network metadata is unavailable right now.')
      return
    }

    const ethereum = resolveEthereum()
    if (!ethereum) {
      setError('No wallet provider found. Connect MetaMask, open this page in a wallet browser, or use WalletConnect on /wallet.')
      return
    }

    const result = await watchTokenInWallet(
      ethereum,
      {
        chainId,
        address,
        symbol,
        decimals,
        logoURI,
      },
      network,
    )

    if (!result.ok) {
      setError(result.error || 'Could not add token to wallet.')
      return
    }

    setStatus(
      result.added
        ? `Added ${symbol} on ${network.chainName}. Stay on that network to see balances.`
        : `${symbol} request was dismissed.`,
    )
  }

  const buttonClass =
    variant === 'primary'
      ? 'rounded bg-primary-600 px-4 py-2 text-sm font-medium text-white hover:bg-primary-700 disabled:opacity-50'
      : 'rounded border border-gray-300 px-4 py-2 text-sm font-medium text-gray-800 hover:bg-gray-50 disabled:opacity-50 dark:border-gray-600 dark:text-gray-100 dark:hover:bg-gray-900'

  return (
    <div className={`space-y-2 ${className}`}>
      <div className="flex flex-wrap gap-2">
        {chainId === 138 ? (
          <button
            type="button"
            onClick={() => void addChainOnly()}
            className={`${buttonClass} ${MOBILE_WALLET_BUTTON_CLASS}`}
          >
            Add Chain 138
          </button>
        ) : null}
        <button
          type="button"
          onClick={() => void addToken()}
          className={`${buttonClass} ${MOBILE_WALLET_BUTTON_CLASS}`}
          aria-label={name ? `Add ${name} to wallet` : `Add ${symbol} to wallet`}
        >
          Add {symbol} to wallet
        </button>
      </div>
      {status ? <p className="text-sm text-green-600 dark:text-green-400">{status}</p> : null}
      {error ? <p className="text-sm text-red-600 dark:text-red-400">{error}</p> : null}
    </div>
  )
}
