import { getAddress } from 'ethers';

export type UniswapTokenListVersion = {
  major: number;
  minor: number;
  patch: number;
};

const TOKEN_EXTENSION_TOP_LEVEL_KEYS = [
  'type',
  'originalLogoURI',
  'registryFamily',
  'familySymbol',
  'deploymentVersion',
  'deploymentStatus',
  'preferredForX402',
] as const;

/** Wallet/registry-facing names for mainnet transport tokens. */
export const MAINNET_PUBLIC_DISPLAY_NAMES: Record<string, string> = {
  cWUSDC: 'Wrapped cUSDC',
  cWUSDT: 'Wrapped cUSDT',
};

export function normalizeTokenListVersion(version: unknown): UniswapTokenListVersion {
  if (version && typeof version === 'object' && 'major' in version) {
    const record = version as { major?: unknown; minor?: unknown; patch?: unknown };
    return {
      major: Number(record.major ?? 1),
      minor: Number(record.minor ?? 0),
      patch: Number(record.patch ?? 0),
    };
  }

  if (typeof version === 'string' && version.trim() !== '') {
    const [major = '1', minor = '0', patch = '0'] = version.trim().split('.');
    return {
      major: Number.parseInt(major, 10) || 1,
      minor: Number.parseInt(minor, 10) || 0,
      patch: Number.parseInt(patch, 10) || 0,
    };
  }

  return { major: 1, minor: 0, patch: 0 };
}

export function checksumTokenAddress(address: string): string {
  try {
    return getAddress(address);
  } catch {
    return address;
  }
}

export function toUniswapTokenListToken(
  token: Record<string, unknown>,
  options?: { displayNames?: Record<string, string> }
): Record<string, unknown> {
  const extensions: Record<string, unknown> = {};

  for (const key of TOKEN_EXTENSION_TOP_LEVEL_KEYS) {
    if (token[key] !== undefined) {
      extensions[key] = token[key];
    }
  }

  if (token.extensions && typeof token.extensions === 'object' && !Array.isArray(token.extensions)) {
    Object.assign(extensions, token.extensions as Record<string, unknown>);
  }

  const symbol = String(token.symbol ?? '');
  const displayName = options?.displayNames?.[symbol];
  const out: Record<string, unknown> = {
    chainId: token.chainId,
    address: checksumTokenAddress(String(token.address ?? '')),
    name: displayName ?? token.name,
    symbol,
    decimals: token.decimals,
  };

  if (token.logoURI) out.logoURI = token.logoURI;
  if (Array.isArray(token.tags) && token.tags.length > 0) out.tags = token.tags;
  if (Object.keys(extensions).length > 0) out.extensions = extensions;

  return out;
}

export function buildUniswapTokenList(params: {
  name: string;
  version: unknown;
  timestamp: string;
  logoURI?: string;
  tokens: Array<Record<string, unknown>>;
  keywords?: string[];
  tags?: Record<string, unknown>;
  displayNames?: Record<string, string>;
}): Record<string, unknown> {
  const body: Record<string, unknown> = {
    name: params.name,
    timestamp: params.timestamp,
    version: normalizeTokenListVersion(params.version),
    tokens: params.tokens.map((token) =>
      toUniswapTokenListToken(token, { displayNames: params.displayNames })
    ),
  };

  if (params.logoURI) body.logoURI = params.logoURI;
  if (params.keywords?.length) body.keywords = params.keywords;
  if (params.tags && Object.keys(params.tags).length > 0) body.tags = params.tags;

  return body;
}

export function resolveTokenListName(chainIds: number[], defaultName: string): string {
  if (chainIds.length === 1 && chainIds[0] === 1) {
    return 'DBIS Ethereum Mainnet GRU';
  }
  return defaultName;
}
