import { getTokenAggregationApiBase } from '@/services/api/tokenAggregation'

export interface TokenMappingPair {
  fromChainId: number
  toChainId: number
  notes?: string
}

export interface TokenMappingPairsResponse {
  pairs: TokenMappingPair[]
}

export interface TokenMappingResolveResponse {
  fromChainId: number
  toChainId: number
  addressOnSource: string
  addressOnTarget: string | null
  activeTransportEligible?: boolean
  gruTransportRuntimeReady?: boolean
  gruTransportFamilyKey?: string | null
  gruTransportCanonicalToken?: Record<string, unknown> | null
}

export async function fetchTokenMappingPairs(): Promise<TokenMappingPair[]> {
  try {
    const response = await fetch(`${getTokenAggregationApiBase()}/token-mapping/pairs`, { cache: 'no-store' })
    if (!response.ok) return []
    const body = (await response.json()) as TokenMappingPairsResponse
    return Array.isArray(body.pairs) ? body.pairs : []
  } catch {
    return []
  }
}

export async function resolveTokenMapping(
  fromChainId: number,
  toChainId: number,
  address: string,
): Promise<TokenMappingResolveResponse | null> {
  const normalized = address.trim()
  if (!/^0x[a-fA-F0-9]{40}$/.test(normalized)) return null
  try {
    const params = new URLSearchParams({
      fromChain: String(fromChainId),
      toChain: String(toChainId),
      address: normalized,
    })
    const response = await fetch(`${getTokenAggregationApiBase()}/token-mapping/resolve?${params}`, {
      cache: 'no-store',
    })
    if (!response.ok) return null
    return (await response.json()) as TokenMappingResolveResponse
  } catch {
    return null
  }
}

export function getMeshDestinationChainIds(pairs: TokenMappingPair[], hubChainId = 138): number[] {
  const ids = new Set<number>([hubChainId])
  for (const pair of pairs) {
    if (pair.fromChainId === hubChainId) ids.add(pair.toChainId)
    if (pair.toChainId === hubChainId) ids.add(pair.fromChainId)
  }
  return [...ids].sort((left, right) => {
    if (left === hubChainId) return -1
    if (right === hubChainId) return 1
    return left - right
  })
}

export async function resolveMeshFromHub(
  hubChainId: number,
  hubAddress: string,
  destinationChainIds: number[],
): Promise<Map<number, string>> {
  const byChain = new Map<number, string>()
  byChain.set(hubChainId, hubAddress)

  await Promise.all(
    destinationChainIds
      .filter((chainId) => chainId !== hubChainId)
      .map(async (chainId) => {
        const resolved = await resolveTokenMapping(hubChainId, chainId, hubAddress)
        const target = resolved?.addressOnTarget?.trim()
        if (target && /^0x[a-fA-F0-9]{40}$/.test(target) && target !== '0x0000000000000000000000000000000000000000') {
          byChain.set(chainId, target)
        }
      }),
  )

  return byChain
}
