import { tokenAggregationApi, type TokenAggregationTokenSnapshot } from './tokenAggregation'

interface NativeAssetDescriptor {
  symbol: string
  pricingAddress: string
}

const NATIVE_ASSET_BY_CHAIN_ID: Record<number, NativeAssetDescriptor> = {
  138: {
    symbol: 'ETH',
    pricingAddress: '0xc02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  },
}

export function getNativeAssetDescriptor(chainId: number): NativeAssetDescriptor {
  return NATIVE_ASSET_BY_CHAIN_ID[chainId] || { symbol: 'ETH', pricingAddress: NATIVE_ASSET_BY_CHAIN_ID[138].pricingAddress }
}

export async function getNativeAssetMarketSafe(
  chainId: number,
): Promise<{ ok: boolean; data: TokenAggregationTokenSnapshot | null }> {
  const descriptor = getNativeAssetDescriptor(chainId)
  return tokenAggregationApi.getTokenSafe(chainId, descriptor.pricingAddress)
}

export async function getNativeAssetPriceAtSafe(
  chainId: number,
  timestamp: string,
): Promise<{ ok: boolean; data: Awaited<ReturnType<typeof tokenAggregationApi.getPriceAtSafe>>['data'] }> {
  const descriptor = getNativeAssetDescriptor(chainId)
  return tokenAggregationApi.getPriceAtSafe(chainId, descriptor.pricingAddress, timestamp)
}

function decimalToScaledInteger(value: number, scale: number): { scaled: bigint; scale: bigint } | null {
  if (!Number.isFinite(value)) {
    return null
  }

  const normalized = value.toFixed(scale)
  const negative = normalized.startsWith('-')
  const unsigned = negative ? normalized.slice(1) : normalized
  const [whole, fraction = ''] = unsigned.split('.')

  try {
    const scaled = BigInt(whole + fraction.padEnd(scale, '0'))
    return {
      scaled: negative ? -scaled : scaled,
      scale: 10n ** BigInt(scale),
    }
  } catch {
    return null
  }
}

function formatScaledUsd(
  rawAmount: string,
  tokenDecimals: number,
  priceUsd: number,
  priceScale = 8,
  outputScale = 6,
): string | undefined {
  if (!rawAmount || !Number.isFinite(priceUsd) || tokenDecimals < 0) {
    return undefined
  }

  try {
    const amount = BigInt(rawAmount)
    const parsedPrice = decimalToScaledInteger(priceUsd, priceScale)
    if (!parsedPrice) {
      return undefined
    }

    const numerator = amount * parsedPrice.scaled * (10n ** BigInt(outputScale))
    const denominator = (10n ** BigInt(tokenDecimals)) * parsedPrice.scale
    const rounded = (numerator + (denominator / 2n)) / denominator
    const divisor = 10n ** BigInt(outputScale)
    const whole = rounded / divisor
    const fraction = (rounded % divisor).toString().padStart(outputScale, '0').replace(/0+$/, '')

    return fraction ? `${whole.toString()}.${fraction}` : whole.toString()
  } catch {
    return undefined
  }
}

export function estimateNativeUsdValue(
  valueWei: string | null | undefined,
  priceUsd: number | undefined,
): string | undefined {
  return valueWei && priceUsd != null ? formatScaledUsd(valueWei, 18, priceUsd) : undefined
}

export function estimateTokenUsdValue(
  rawAmount: string | null | undefined,
  decimals: number,
  priceUsd: number | undefined,
): string | undefined {
  return rawAmount && priceUsd != null ? formatScaledUsd(rawAmount, decimals, priceUsd) : undefined
}
