/** Shared detection + provider resolution for mobile wallets and in-app browsers. */

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

/** Accept WalletConnect / injected providers with slightly different request typings. */
export function asWalletEthereumProvider(provider: unknown): EthereumProvider | undefined {
  if (!provider || typeof provider !== 'object') return undefined
  const candidate = provider as { request?: unknown }
  if (typeof candidate.request !== 'function') return undefined
  return provider as EthereumProvider
}

const MOBILE_UA_RE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i

export function isMobileUserAgent(userAgent: string): boolean {
  return MOBILE_UA_RE.test(userAgent)
}

/** True for phone/tablet browsers (not a guarantee of in-app wallet). */
export function isMobileBrowser(userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''): boolean {
  return isMobileUserAgent(userAgent)
}

export function isWalletInAppBrowser(userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''): boolean {
  const ua = userAgent.toLowerCase()
  return (
    ua.includes('metamask') ||
    ua.includes('trust') ||
    ua.includes('imtoken') ||
    ua.includes('coinbase') ||
    ua.includes('rainbow') ||
    ua.includes('status') ||
    ua.includes('phantom') ||
    ua.includes('zerion')
  )
}

export function isMobileWalletContext(userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''): boolean {
  return isMobileBrowser(userAgent) || isWalletInAppBrowser(userAgent)
}

export function resolveInjectedEthereumProvider(
  win: Window & { ethereum?: EthereumProvider } = typeof window !== 'undefined'
    ? (window as Window & { ethereum?: EthereumProvider })
    : ({} as Window & { ethereum?: EthereumProvider }),
): EthereumProvider | undefined {
  const eth = win.ethereum
  if (!eth) return undefined

  const providers = Array.isArray(eth.providers) ? eth.providers.filter(Boolean) : []
  if (providers.length > 0) {
    const metamask = providers.find((provider) => provider.isMetaMask)
    return metamask || providers[0]
  }

  return eth
}

export function resolveWalletEthereumProvider(
  walletConnectProvider?: unknown,
  win: Window & { ethereum?: EthereumProvider } = typeof window !== 'undefined'
    ? (window as Window & { ethereum?: EthereumProvider })
    : ({} as Window & { ethereum?: EthereumProvider }),
): EthereumProvider | undefined {
  return resolveInjectedEthereumProvider(win) ?? asWalletEthereumProvider(walletConnectProvider)
}

/** MetaMask mobile deep link — opens the in-app dApp browser (required for EIP-747 on mobile Safari/Chrome). */
export function buildMetaMaskMobileDappUrl(pageUrl: string): string {
  try {
    const parsed = new URL(pageUrl)
    const hostPath = `${parsed.host}${parsed.pathname}${parsed.search}${parsed.hash}`
    return `https://metamask.app.link/dapp/${hostPath.replace(/^\/+/, '')}`
  } catch {
    const stripped = pageUrl.replace(/^https?:\/\//i, '')
    return `https://metamask.app.link/dapp/${stripped}`
  }
}

export function buildCoinbaseWalletDappUrl(pageUrl: string): string {
  return `https://go.cb-w.com/dapp?cb_url=${encodeURIComponent(pageUrl)}`
}

/** Delay between sequential wallet_watchAsset prompts — mobile wallets reject rapid-fire RPC. */
export function getWatchAssetInterPromptDelayMs(mobile = isMobileWalletContext()): number {
  return mobile ? 650 : 120
}

/** Tokens per user gesture on mobile; desktop runs the full list in one click. */
export function getWatchAssetBatchSize(mobile = isMobileWalletContext()): number {
  return mobile ? 2 : Number.POSITIVE_INFINITY
}

export function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => {
    const timer = typeof window !== 'undefined' ? window.setTimeout : setTimeout
    timer(resolve, ms)
  })
}

export const MOBILE_WALLET_BUTTON_CLASS =
  'min-h-[44px] touch-manipulation select-none active:scale-[0.98]'
