import { LiveAggregatorRoute } from '../config/aggregator-route-matrix';

export type PartnerName = '1inch' | '0x' | 'LiFi';

export interface PartnerAdapterContext {
  amount: string;
  takerAddress?: string;
  fromAddress?: string;
  toAddress?: string;
  recipient?: string;
  slippagePercent?: string;
  slippageBps?: string;
}

export interface PartnerPayloadResult {
  partner: PartnerName;
  routeId: string;
  supported: boolean;
  reason?: string;
  endpoint: string;
  method: 'GET';
  headers: Record<string, string>;
  query: Record<string, string>;
  route: LiveAggregatorRoute;
  docs: string[];
}

const ONE_INCH_SUPPORTED_CHAINS = new Set([
  1, 10, 56, 100, 130, 137, 146, 324, 501, 8453, 43114, 42161, 59144,
]);

const ZERO_X_SUPPORTED_CHAINS = new Set([
  1, 10, 56, 130, 137, 8453, 42161, 43114,
]);

function defaultAddress(address?: string): string {
  return address || '0x000000000000000000000000000000000000dEaD';
}

function getSellToken(route: LiveAggregatorRoute): string | null {
  return route.tokenInAddress || route.assetAddress || null;
}

function getBuyToken(route: LiveAggregatorRoute): string | null {
  return route.tokenOutAddress || route.assetAddress || null;
}

export function build1inchClassicSwapPayload(
  route: LiveAggregatorRoute,
  context: PartnerAdapterContext
): PartnerPayloadResult {
  const src = getSellToken(route);
  const dst = getBuyToken(route);
  const supported = route.routeType === 'swap' && route.fromChainId === route.toChainId && ONE_INCH_SUPPORTED_CHAINS.has(route.fromChainId);
  const endpoint = `https://api.1inch.com/swap/v6.1/${route.fromChainId}/swap`;

  return {
    partner: '1inch',
    routeId: route.routeId,
    supported,
    reason: supported
      ? undefined
      : '1inch Classic Swap does not document support for this route chain or route type; Chain 138 is not in the published supported chain list.',
    endpoint,
    method: 'GET',
    headers: {
      Accept: 'application/json',
      Authorization: 'Bearer <ONE_INCH_API_KEY>',
    },
    query: {
      src: src || '',
      dst: dst || '',
      amount: context.amount,
      from: defaultAddress(context.fromAddress || context.takerAddress),
      slippage: context.slippagePercent || '1',
      disableEstimate: 'false',
      allowPartialFill: 'false',
    },
    route,
    docs: [
      'https://business.1inch.com/portal/documentation/apis/swap/classic-swap/quick-start',
      'https://business.1inch.com/portal/documentation/apis/swap/classic-swap/introduction',
    ],
  };
}

export function buildZeroXAllowanceHolderPricePayload(
  route: LiveAggregatorRoute,
  context: PartnerAdapterContext
): PartnerPayloadResult {
  const sellToken = getSellToken(route);
  const buyToken = getBuyToken(route);
  const supported = route.routeType === 'swap' && route.fromChainId === route.toChainId && ZERO_X_SUPPORTED_CHAINS.has(route.fromChainId);

  return {
    partner: '0x',
    routeId: route.routeId,
    supported,
    reason: supported
      ? undefined
      : '0x Swap API supports published EVM chains, but this route chain is not in the current public support set; Chain 138 is unsupported.',
    endpoint: 'https://api.0x.org/swap/allowance-holder/price',
    method: 'GET',
    headers: {
      '0x-api-key': '<ZEROX_API_KEY>',
      '0x-version': 'v2',
      Accept: 'application/json',
    },
    query: {
      chainId: String(route.fromChainId),
      sellToken: sellToken || '',
      buyToken: buyToken || '',
      sellAmount: context.amount,
      taker: defaultAddress(context.takerAddress || context.fromAddress),
      recipient: defaultAddress(context.recipient || context.toAddress || context.takerAddress || context.fromAddress),
      slippageBps: context.slippageBps || '100',
    },
    route,
    docs: [
      'https://docs.0x.org/api-reference/openapi-yaml/gasless/getprice',
      'https://docs.0x.org/docs/0x-swap-api/additional-topics/how-to-set-your-token-allowances',
    ],
  };
}

export function buildLiFiQuotePayload(
  route: LiveAggregatorRoute,
  context: PartnerAdapterContext
): PartnerPayloadResult {
  const fromToken = getSellToken(route);
  const toToken = getBuyToken(route);
  const supported = route.fromChainId !== 138 && route.toChainId !== 138 && route.fromChainId !== 651940 && route.toChainId !== 651940;

  return {
    partner: 'LiFi',
    routeId: route.routeId,
    supported,
    reason: supported
      ? undefined
      : 'LI.FI quote payload shape is valid, but this route depends on a custom chain not documented in LI.FI public chain support.',
    endpoint: 'https://li.quest/v1/quote',
    method: 'GET',
    headers: {
      Accept: 'application/json',
      'x-lifi-api-key': '<LIFI_API_KEY_OPTIONAL>',
    },
    query: {
      fromChain: String(route.fromChainId),
      toChain: String(route.toChainId),
      fromToken: fromToken || '',
      toToken: toToken || '',
      fromAmount: context.amount,
      fromAddress: defaultAddress(context.fromAddress || context.takerAddress),
      toAddress: defaultAddress(context.toAddress || context.recipient || context.fromAddress || context.takerAddress),
      slippage: context.slippagePercent || '0.03',
    },
    route,
    docs: [
      'https://docs.li.fi/api-reference/introduction',
      'https://docs.li.fi/agents/overview',
    ],
  };
}

export function buildPartnerPayload(
  partner: PartnerName,
  route: LiveAggregatorRoute,
  context: PartnerAdapterContext
): PartnerPayloadResult {
  switch (partner) {
    case '1inch':
      return build1inchClassicSwapPayload(route, context);
    case '0x':
      return buildZeroXAllowanceHolderPricePayload(route, context);
    case 'LiFi':
      return buildLiFiQuotePayload(route, context);
  }
}
