import type { RateData, RateEntry } from '../shared/types';
import { safeBig } from '../../math/decimal';
import type Big from 'big.js';

function getRate(
  code: string,
  base: string,
  rates: Record<string, RateEntry>,
  pricing: 'mid' | 'bidask',
  direction: 'from' | 'to'
): Big | null {
  if (code === base) return safeBig('1');

  const entry = rates[code];
  if (!entry) return null;

  if (pricing === 'bidask') {
    const key = direction === 'from' ? 'ask' : 'bid';
    const rate = safeBig(String(entry[key]));
    if (rate.gt('0')) return rate;
  }

  const mid = safeBig(String(entry.mid));
  return mid.gt('0') ? mid : null;
}

function hasFullBidAsk(
  code: string,
  base: string,
  rates: Record<string, RateEntry>
): boolean {
  if (code === base) return true;
  const entry = rates[code];
  if (!entry) {
    return false;
  }

  return safeBig(String(entry.bid)).gt('0') && safeBig(String(entry.ask)).gt('0');
}

export function getPairPricing(
  from: string,
  to: string,
  data: RateData
): 'mid' | 'bidask' {
  const fromHasBidAsk = hasFullBidAsk(from, data.base, data.rates);
  const toHasBidAsk = hasFullBidAsk(to, data.base, data.rates);
  return fromHasBidAsk && toHasBidAsk ? 'bidask' : 'mid';
}

export function convertAmount(
  amount: string | Big,
  from: string,
  to: string,
  data: RateData
): Big | null {
  const amountValue = safeBig(amount);
  if (from === to) return amountValue;

  const pricingMode = getPairPricing(from, to, data);

  const fromRate = getRate(from, data.base, data.rates, pricingMode, 'from');
  const toRate = getRate(to, data.base, data.rates, pricingMode, 'to');

  if (fromRate === null || toRate === null || fromRate.lte('0')) return null;

  const raw = amountValue.times(toRate).div(fromRate);
  const percent = safeBig(String(data.adjustmentPercent ?? '0'));

  if (percent.eq('0')) {
    return raw;
  }

  const multiplier = percent.div('100').plus('1');
  return raw.times(multiplier);
}
