import { Token } from "../entities/token";
import { Price } from "../entities/fractions/price";
import JSBI from "jsbi";
import { Q128 } from "../internalConstants";
import { encodeSqrtRatioX64 } from "./encodeSqrtRatioX64";
import { TickMath } from "./tickMath";

/**
 * Returns a price object corresponding to the input tick and the base/quote token
 * Inputs must be tokens because the address order is used to interpret the price represented by the tick
 * @param baseToken the base token of the price
 * @param quoteToken the quote token of the price
 * @param tick the tick for which to return the price
 */
export function tickToPrice(
  baseToken: Token,
  quoteToken: Token,
  tick: number
): Price<Token, Token> {
  const sqrtRatioX64 = TickMath.getSqrtRatioAtTick(tick);

  const ratioX128 = JSBI.multiply(sqrtRatioX64, sqrtRatioX64);

  return baseToken.sortsBefore(quoteToken)
    ? new Price(baseToken, quoteToken, Q128, ratioX128)
    : new Price(baseToken, quoteToken, ratioX128, Q128);
}

/**
 * Returns the first tick for which the given price is greater than or equal to the tick price
 * @param price for which to return the closest tick that represents a price less than or equal to the input price,
 * i.e. the price of the returned tick is less than or equal to the input price
 */
export function priceToClosestTick(price: Price<Token, Token>): number {
  const sorted = price.baseCurrency.sortsBefore(price.quoteCurrency);

  const sqrtRatioX64 = sorted
    ? encodeSqrtRatioX64(price.numerator, price.denominator)
    : encodeSqrtRatioX64(price.denominator, price.numerator);

  let tick = TickMath.getTickAtSqrtRatio(sqrtRatioX64);
  const nextTickPrice = tickToPrice(
    price.baseCurrency,
    price.quoteCurrency,
    tick + 1
  );
  if (sorted) {
    if (!price.lessThan(nextTickPrice)) {
      tick++;
    }
  } else {
    if (!price.greaterThan(nextTickPrice)) {
      tick++;
    }
  }
  return tick;
}
