import { Price, TokenAmount } from "@saberhq/token-utils";
import BN from "bn.js";

import type { IExchangeInfo } from "../index.js";
import { calculateEstimatedSwapOutputAmount } from "../index.js";

/**
 * Gets the price of the second token in the swap, i.e. "Token 1", with respect to "Token 0".
 *
 * To get the price of "Token 0", use `.invert()` on the result of this function.
 * @returns
 */
export const calculateSwapPrice = (exchangeInfo: IExchangeInfo): Price => {
  const reserve0 = exchangeInfo.reserves[0].amount;
  const reserve1 = exchangeInfo.reserves[1].amount;

  // We try to get at least 4 decimal points of precision here
  // Otherwise, we attempt to swap 1% of total supply of the pool
  // or at most, $1
  const inputAmountNum = Math.max(
    10_000,
    Math.min(
      10 ** reserve0.token.decimals,
      Math.floor(parseInt(reserve0.toU64().div(new BN(100)).toString())),
    ),
  );

  const inputAmount = new TokenAmount(reserve0.token, inputAmountNum);
  const outputAmount = calculateEstimatedSwapOutputAmount(
    exchangeInfo,
    inputAmount,
  );

  const frac = outputAmount.outputAmountBeforeFees.asFraction.divide(
    inputAmount.asFraction,
  );

  return new Price(
    reserve0.token,
    reserve1.token,
    frac.denominator,
    frac.numerator,
  );
};
