'use client'

import { useEffect, useMemo, useState } from 'react'

type WalletChain = {
  chainId: string
  chainIdDecimal?: number
  chainName: string
  rpcUrls: string[]
  blockExplorerUrls: string[]
  iconUrls?: string[]
  nativeCurrency: {
    name: string
    symbol: string
    decimals: number
  }
  shortName?: string
  infoURL?: string
  explorerApiUrl?: string
}

type TokenListToken = {
  chainId: number
  address: string
  name: string
  symbol: string
  decimals: number
  logoURI?: string
  tags?: string[]
  extensions?: Record<string, unknown>
}

type NetworksCatalog = {
  name?: string
  version?: {
    major?: number
    minor?: number
    patch?: number
  }
  defaultChainId?: number
  chains?: WalletChain[]
}

type TokenListCatalog = {
  name?: string
  version?: {
    major?: number
    minor?: number
    patch?: number
  }
  keywords?: string[]
  tokens?: TokenListToken[]
}

type EthereumProvider = {
  request: (args: { method: string; params?: unknown[] }) => Promise<unknown>
}

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', 'https://rpc.d-bis.org', 'https://rpc2.d-bis.org'],
  blockExplorerUrls: ['https://explorer.d-bis.org'],
  iconUrls: ['https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png'],
  shortName: 'dbis',
  infoURL: 'https://explorer.d-bis.org',
  explorerApiUrl: 'https://explorer.d-bis.org/api/v2',
}

const FALLBACK_ETHEREUM: WalletChain = {
  chainId: '0x1',
  chainIdDecimal: 1,
  chainName: 'Ethereum Mainnet',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: ['https://eth.llamarpc.com', 'https://rpc.ankr.com/eth', 'https://ethereum.publicnode.com'],
  blockExplorerUrls: ['https://etherscan.io'],
  iconUrls: ['https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png'],
  shortName: 'eth',
  infoURL: 'https://ethereum.org',
}

const FALLBACK_ALL_MAINNET: WalletChain = {
  chainId: '0x9f2c4',
  chainIdDecimal: 651940,
  chainName: 'ALL Mainnet',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: ['https://mainnet-rpc.alltra.global'],
  blockExplorerUrls: ['https://alltra.global'],
  iconUrls: ['https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png'],
  shortName: 'all',
  infoURL: 'https://alltra.global',
}

const FEATURED_TOKEN_SYMBOLS = ['cUSDT', 'cUSDC', 'USDT', 'USDC', 'cXAUC', 'cXAUT']

function getApiBase() {
  if (typeof window !== 'undefined') {
    return process.env.NEXT_PUBLIC_API_URL || window.location.origin
  }
  return process.env.NEXT_PUBLIC_API_URL || 'https://explorer.d-bis.org'
}

export function AddToMetaMask() {
  const [status, setStatus] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [networks, setNetworks] = useState<NetworksCatalog | null>(null)
  const [tokenList, setTokenList] = useState<TokenListCatalog | null>(null)

  const ethereum = typeof window !== 'undefined'
    ? (window as unknown as { ethereum?: EthereumProvider }).ethereum
    : undefined

  const apiBase = getApiBase().replace(/\/$/, '')
  const tokenListUrl = `${apiBase}/api/config/token-list`
  const networksUrl = `${apiBase}/api/config/networks`

  useEffect(() => {
    let active = true

    async function loadCatalogs() {
      try {
        const [networksResponse, tokenListResponse] = await Promise.all([
          fetch(networksUrl),
          fetch(tokenListUrl),
        ])

        const [networksJson, tokenListJson] = await Promise.all([
          networksResponse.ok ? networksResponse.json() : null,
          tokenListResponse.ok ? tokenListResponse.json() : null,
        ])

        if (!active) return
        setNetworks(networksJson)
        setTokenList(tokenListJson)
      } catch {
        if (!active) return
        setNetworks(null)
        setTokenList(null)
      }
    }

    loadCatalogs()

    return () => {
      active = false
    }
  }, [networksUrl, tokenListUrl])

  const chains = useMemo(() => {
    const chainMap = new Map<number, WalletChain>()
    for (const chain of networks?.chains || []) {
      if (typeof chain.chainIdDecimal === 'number') {
        chainMap.set(chain.chainIdDecimal, chain)
      }
    }

    return {
      chain138: chainMap.get(138) || FALLBACK_CHAIN_138,
      ethereum: chainMap.get(1) || FALLBACK_ETHEREUM,
      allMainnet: chainMap.get(651940) || FALLBACK_ALL_MAINNET,
      total: (networks?.chains || []).length,
    }
  }, [networks])

  const featuredTokens = useMemo(() => {
    const tokenMap = new Map<string, TokenListToken>()
    for (const token of tokenList?.tokens || []) {
      if (token.chainId !== 138) continue
      if (!FEATURED_TOKEN_SYMBOLS.includes(token.symbol)) continue
      tokenMap.set(token.symbol, token)
    }

    return FEATURED_TOKEN_SYMBOLS
      .map((symbol) => tokenMap.get(symbol))
      .filter((token): token is TokenListToken => !!token)
  }, [tokenList])

  const addChain = async (chain: WalletChain) => {
    setError(null)
    setStatus(null)

    if (!ethereum) {
      setError('MetaMask or another Web3 wallet is not installed.')
      return
    }

    try {
      await ethereum.request({
        method: 'wallet_addEthereumChain',
        params: [chain],
      })
      setStatus(`Added ${chain.chainName}. You can switch to it in your wallet.`)
    } catch (e) {
      const err = e as { code?: number; message?: string }
      if (err.code === 4902) {
        setStatus(`Added ${chain.chainName}. You can switch to it in your wallet.`)
      } else {
        setError(err.message || `Failed to add ${chain.chainName}.`)
      }
    }
  }

  const watchToken = async (token: TokenListToken) => {
    setError(null)
    setStatus(null)

    if (!ethereum) {
      setError('MetaMask or another Web3 wallet is not installed.')
      return
    }

    try {
      const added = await ethereum.request({
        method: 'wallet_watchAsset',
        params: [{
          type: 'ERC20',
          options: {
            address: token.address,
            symbol: token.symbol,
            decimals: token.decimals,
            image: token.logoURI,
          },
        }],
      })

      setStatus(added ? `Added ${token.symbol} to your wallet.` : `${token.symbol} request was dismissed.`)
    } catch (e) {
      const err = e as { message?: string }
      setError(err.message || `Failed to add ${token.symbol}.`)
    }
  }

  const copyText = async (value: string, label: string) => {
    setError(null)
    setStatus(null)

    try {
      await navigator.clipboard.writeText(value)
      setStatus(`Copied ${label}.`)
    } catch {
      setError(`Could not copy ${label}.`)
    }
  }

  const tokenCount138 = (tokenList?.tokens || []).filter((token) => token.chainId === 138).length
  const metadataKeywordString = (tokenList?.keywords || []).join(', ')

  return (
    <div className="space-y-4 rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-800">
      <h2 className="text-lg font-semibold">Add to MetaMask</h2>
      <p className="text-sm text-gray-600 dark:text-gray-400">
        The wallet tools now read the same explorer-served network catalog and token list that MetaMask can consume.
        That keeps chain metadata, token metadata, and optional extensions aligned with the live explorer API instead of
        relying on stale frontend-only defaults.
      </p>

      <div className="grid gap-3 md:grid-cols-3">
        <button
          type="button"
          onClick={() => addChain(chains.chain138)}
          className="rounded bg-primary-600 px-4 py-2 text-sm font-medium text-white hover:bg-primary-700"
        >
          Add Chain 138
        </button>
        <button
          type="button"
          onClick={() => addChain(chains.ethereum)}
          className="rounded bg-gray-600 px-4 py-2 text-sm font-medium text-white hover:bg-gray-700"
        >
          Add Ethereum Mainnet
        </button>
        <button
          type="button"
          onClick={() => addChain(chains.allMainnet)}
          className="rounded bg-gray-600 px-4 py-2 text-sm font-medium text-white hover:bg-gray-700"
        >
          Add ALL Mainnet
        </button>
      </div>

      <div className="grid gap-4 lg:grid-cols-2">
        <div className="rounded-lg border border-gray-200 p-4 dark:border-gray-700">
          <div className="text-sm font-semibold text-gray-900 dark:text-white">Explorer-served MetaMask metadata</div>
          <div className="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-400">
            <p>Networks catalog: {chains.total > 0 ? `${chains.total} chains` : 'using frontend fallback values'}</p>
            <p>Chain 138 token entries: {tokenCount138}</p>
            {metadataKeywordString ? <p>Keywords: {metadataKeywordString}</p> : null}
          </div>
          <div className="mt-4 space-y-3">
            <div>
              <p className="mb-1 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Networks config URL</p>
              <code className="block break-all rounded bg-gray-100 p-2 text-xs dark:bg-gray-900">{networksUrl}</code>
              <div className="mt-2 flex flex-wrap gap-2">
                <button type="button" onClick={() => copyText(networksUrl, 'networks config URL')} className="rounded bg-gray-100 px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700">
                  Copy URL
                </button>
                <a href={networksUrl} target="_blank" rel="noopener noreferrer" className="rounded bg-gray-100 px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700">
                  Open JSON
                </a>
              </div>
            </div>
            <div>
              <p className="mb-1 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Token list URL</p>
              <code className="block break-all rounded bg-gray-100 p-2 text-xs dark:bg-gray-900">{tokenListUrl}</code>
              <div className="mt-2 flex flex-wrap gap-2">
                <button type="button" onClick={() => copyText(tokenListUrl, 'token list URL')} className="rounded bg-gray-100 px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700">
                  Copy URL
                </button>
                <a href={tokenListUrl} target="_blank" rel="noopener noreferrer" className="rounded bg-gray-100 px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-200 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-700">
                  Open JSON
                </a>
              </div>
            </div>
          </div>
        </div>

        <div className="rounded-lg border border-gray-200 p-4 dark:border-gray-700">
          <div className="text-sm font-semibold text-gray-900 dark:text-white">Featured Chain 138 tokens</div>
          <p className="mt-2 text-sm text-gray-600 dark:text-gray-400">
            These tokens come from the explorer token list and use `wallet_watchAsset` so the wallet gets the same symbol,
            decimals, image, and optional token metadata that the explorer publishes.
          </p>
          <div className="mt-4 space-y-3">
            {featuredTokens.length === 0 ? (
              <p className="text-sm text-gray-600 dark:text-gray-400">Featured token metadata is not available right now.</p>
            ) : featuredTokens.map((token) => (
              <div key={token.address} className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
                <div className="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
                  <div>
                    <div className="text-sm font-semibold text-gray-900 dark:text-white">
                      {token.symbol} <span className="font-normal text-gray-500 dark:text-gray-400">({token.name})</span>
                    </div>
                    <div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
                      {token.address}
                    </div>
                    <div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
                      Decimals: {token.decimals}
                      {token.tags?.length ? ` • Tags: ${token.tags.join(', ')}` : ''}
                    </div>
                    {typeof token.extensions?.unitDescription === 'string' ? (
                      <div className="mt-1 text-xs text-gray-500 dark:text-gray-400">{token.extensions.unitDescription}</div>
                    ) : null}
                  </div>
                  <button
                    type="button"
                    onClick={() => watchToken(token)}
                    className="rounded bg-primary-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-primary-700"
                  >
                    Add {token.symbol}
                  </button>
                </div>
              </div>
            ))}
          </div>
        </div>
      </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>
  )
}
