import { useWalletBalance, usePortfolio, CHAINS } from '@features/wallet'
import type { Chain, FormattedAmount } from '@features/wallet'
import { useMe } from '@features/auth'
import { getCoinIcon } from '@shared/assets/coins'
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
import { TOKENS, type Token } from './tokens'

const NATIVE_TICKER: Record<Chain, string> = {
  BTC: 'BTC',
  ETH: 'ETH',
  SOL: 'SOL',
  TRX: 'TRX',
  BSC: 'BNB',
}

const NATIVE_NAME: Record<Chain, string> = {
  BTC: 'Bitcoin',
  ETH: 'Ethereum',
  SOL: 'Solana',
  TRX: 'Tron',
  BSC: 'BNB',
}

const DEFAULT_TOKEN_COLOR = '#2A2D3A'

function formatUsd(value: number | null | undefined): string {
  if (value == null) return '$—'
  return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
}

function formatPrice(value: number | null | undefined): string {
  if (value == null) return '$—'
  if (value >= 1) {
    return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
  }
  return `$${value.toLocaleString('en-US', { minimumFractionDigits: 4, maximumFractionDigits: 6 })}`
}

function lookupStatic(ticker: string): Token | undefined {
  return TOKENS.find((t) => t.ticker === ticker)
}

function nativeRowFor(chain: Chain, native: FormattedAmount): Token {
  const ticker = NATIVE_TICKER[chain]
  const staticToken = lookupStatic(ticker)
  return {
    id: `${chain}-${ticker}`,
    chain,
    ticker,
    name: NATIVE_NAME[chain],
    logo: getCoinIcon(ticker) ?? staticToken?.logo,
    color: staticToken?.color ?? DEFAULT_TOKEN_COLOR,
    price: formatPrice(native.usdPrice),
    change: 0,
    bal: truncateDecimals(native.formatted),
    usd: formatUsd(native.usdValue),
    usdValue: native.usdValue,
    fav: false,
  }
}

function tokenRowFor(chain: Chain, symbol: string, amount: FormattedAmount): Token {
  const staticToken = lookupStatic(symbol)
  return {
    id: `${chain}-${symbol}`,
    chain,
    ticker: symbol,
    name: staticToken?.name ?? symbol,
    logo: getCoinIcon(symbol) ?? staticToken?.logo,
    color: staticToken?.color ?? DEFAULT_TOKEN_COLOR,
    price: formatPrice(amount.usdPrice),
    change: 0,
    bal: truncateDecimals(amount.formatted),
    usd: formatUsd(amount.usdValue),
    usdValue: amount.usdValue,
    fav: false,
  }
}

function hasBalance(amount: FormattedAmount): boolean {
  return parseFloat(amount.formatted) > 0
}

export function useChainTokenRows(chain: Chain) {
  const { data, isLoading } = useWalletBalance(chain)

  if (!data) return { rows: [] as Token[], isLoading }

  const nativeRow = nativeRowFor(chain, data.native)
  const tokenRows = Object.entries(data.tokens ?? {}).map(([symbol, amount]) =>
    tokenRowFor(chain, symbol, amount),
  )

  return { rows: [nativeRow, ...tokenRows], isLoading }
}

export function useAllWalletTokenRows() {
  const { data, isLoading } = usePortfolio()
  const { data: me } = useMe()

  // Legal-entity portfolios return a fixed catalog of supported tokens that are
  // usually all zero for a fresh account. Filtering out zero balances would
  // leave this aggregate view blank, so show every wallet/token (matching the
  // per-chain pages). Individuals keep the non-zero-only view to avoid clutter.
  const showAll = me?.account_type === 'legal_entity'

  if (!data) return { rows: [] as Token[], isLoading }

  const rows: Token[] = []

  for (const chain of CHAINS) {
    const chainData = data.perChain?.[chain]
    if (!chainData) continue

    const chainRows: Token[] = []

    if (chainData.native && (showAll || hasBalance(chainData.native))) {
      chainRows.push(nativeRowFor(chain, chainData.native))
    }

    for (const [symbol, amount] of Object.entries(chainData.tokens ?? {})) {
      if (!showAll && !hasBalance(amount)) continue
      chainRows.push(tokenRowFor(chain, symbol, amount))
    }

    // Sort within the network by value; keep networks in CHAINS order so rows
    // stay contiguous per chain for grouping in the table.
    chainRows.sort((a, b) => (b.usdValue ?? 0) - (a.usdValue ?? 0))
    rows.push(...chainRows)
  }

  return { rows, isLoading }
}
