import { BN } from '@ocap/util';

export function trimDecimals(value: string | number, maxDecimals: number): string {
  const num = typeof value === 'number' ? value : parseFloat(value || '0');
  const multiplier = 10 ** maxDecimals;
  const rounded = Math.round(num * multiplier) / multiplier;
  return rounded.toString();
}

/**
 * Limit precision of token amount in smallest unit to avoid meaningless precision
 *
 * For dynamic pricing, we limit precision to at most 10 decimal places in token amount.
 * This is done by rounding to the nearest 10^(decimal - MAX_SIGNIFICANT_DECIMALS) unit.
 *
 * @param amountInSmallestUnit - Amount in token's smallest unit (e.g., wei for 18 decimals)
 * @param tokenDecimals - Token decimal places (e.g., 18 for most ERC20 tokens)
 * @param maxSignificantDecimals - Maximum significant decimal places to keep (default: 10)
 * @returns Rounded amount with limited precision
 *
 * @example
 * // Token with 18 decimals, amount = 1234567890123456789 wei (1.234567890123456789 tokens)
 * // With maxSignificantDecimals = 10, we round to nearest 10^8 wei
 * // Result: 1234567890200000000 wei (1.2345678902 tokens)
 * limitTokenPrecision('1234567890123456789', 18, 10) // Returns BN of 1234567890200000000
 */
export function limitTokenPrecision(
  amountInSmallestUnit: any, // BN type
  tokenDecimals: number,
  maxSignificantDecimals: number = 10
): any {
  const amount = new BN(amountInSmallestUnit.toString());

  // If token has fewer decimals than our max, no need to limit
  if (tokenDecimals <= maxSignificantDecimals) {
    return amount;
  }

  // Calculate the precision unit to round to
  // For example, if tokenDecimals = 18 and maxSignificantDecimals = 6
  // precisionUnit = 10^(18-6) = 10^12
  const precisionExponent = tokenDecimals - maxSignificantDecimals;
  const precisionUnit = new BN(10).pow(new BN(precisionExponent));

  // Round to nearest precisionUnit using ceiling division
  // This ensures we don't undercharge the customer
  // Formula: ceil(amount / precisionUnit) * precisionUnit
  const quotient = amount.add(precisionUnit).sub(new BN(1)).div(precisionUnit);
  const roundedAmount = quotient.mul(precisionUnit);

  return roundedAmount;
}
