"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSqrtRatioAtTick = exports.getAmountsForLiquidity = void 0;
/* eslint-disable no-negated-condition */
/* eslint-disable complexity */
const ethers_1 = require("ethers");
const FixedPoint96 = {
    RESOLUTION: ethers_1.BigNumber.from(2).pow(96),
    Q96: ethers_1.BigNumber.from(2).pow(192),
};
function mulDiv(x, y, z) {
    return x.mul(y).div(z);
}
function getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity) {
    if (sqrtRatioAX96.gt(sqrtRatioBX96)) {
        [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
    }
    return mulDiv(liquidity.shl(96), sqrtRatioBX96.sub(sqrtRatioAX96), sqrtRatioBX96).div(sqrtRatioAX96);
}
function getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity) {
    if (sqrtRatioAX96.gt(sqrtRatioBX96)) {
        [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
    }
    return mulDiv(liquidity, sqrtRatioBX96.sub(sqrtRatioAX96), FixedPoint96.Q96);
}
function getAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity) {
    if (sqrtRatioAX96.gt(sqrtRatioBX96)) {
        [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
    }
    let amount0 = ethers_1.BigNumber.from(0);
    let amount1 = ethers_1.BigNumber.from(0);
    if (sqrtRatioX96.lte(sqrtRatioAX96)) {
        amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
    }
    else if (sqrtRatioX96.lt(sqrtRatioBX96)) {
        amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);
        amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);
    }
    else {
        amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
    }
    return [amount0, amount1];
}
exports.getAmountsForLiquidity = getAmountsForLiquidity;
const MaxUint256 = ethers_1.BigNumber.from('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
const Q32 = ethers_1.BigNumber.from(2).pow(32);
const ZERO = ethers_1.BigNumber.from(0);
const ONE = ethers_1.BigNumber.from(1);
function mulShift(x, y) {
    return x.mul(ethers_1.BigNumber.from(y)).div(MaxUint256);
}
/**
 * Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick
 * @param tick the tick for which to compute the sqrt ratio
 */
function getSqrtRatioAtTick(tick) {
    if (tick < -887272 || tick > 887272 || !Number.isInteger(tick)) {
        throw new Error('TICK');
    }
    const absTick = tick < 0 ? tick * -1 : tick;
    let ratio = (absTick & 0x1) !== 0 ?
        ethers_1.BigNumber.from('0xfffcb933bd6fad37aa2d162d1a594001') :
        ethers_1.BigNumber.from('0x100000000000000000000000000000000');
    if ((absTick & 0x2) !== 0)
        ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a');
    if ((absTick & 0x4) !== 0)
        ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc');
    if ((absTick & 0x8) !== 0)
        ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0');
    if ((absTick & 0x10) !== 0)
        ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644');
    if ((absTick & 0x20) !== 0)
        ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0');
    if ((absTick & 0x40) !== 0)
        ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861');
    if ((absTick & 0x80) !== 0)
        ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053');
    if ((absTick & 256) !== 0)
        ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4');
    if ((absTick & 512) !== 0)
        ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54');
    if ((absTick & 1024) !== 0)
        ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3');
    if ((absTick & 2048) !== 0)
        ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9');
    if ((absTick & 4096) !== 0)
        ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825');
    if ((absTick & 8192) !== 0)
        ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5');
    if ((absTick & 16384) !== 0)
        ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7');
    if ((absTick & 32768) !== 0)
        ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6');
    if ((absTick & 65536) !== 0)
        ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9');
    if ((absTick & 131072) !== 0)
        ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604');
    if ((absTick & 262144) !== 0)
        ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98');
    if ((absTick & 524288) !== 0)
        ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2');
    if (tick > 0)
        ratio = MaxUint256.div(ratio);
    // back to Q96
    return ratio.mod(Q32).gt(ZERO) ? ratio.div(Q32).add(ONE) : ratio.div(Q32);
}
exports.getSqrtRatioAtTick = getSqrtRatioAtTick;
