import { LAMPORTS_PER_SOL } from '@solarti/web3.js';
import BN from 'bn.js';
import { toBigNumber } from './BigNumber';
import { CurrencyMismatchError, UnexpectedCurrencyError } from '../errors';
/** @group Constants */
export const SOL = {
    symbol: 'SOL',
    decimals: 9,
};
/** @group Constants */
export const USD = {
    symbol: 'USD',
    decimals: 2,
};
export const amount = (basisPoints, currency) => {
    return {
        basisPoints: toBigNumber(basisPoints),
        currency,
    };
};
export const lamports = (lamports) => {
    return amount(lamports, SOL);
};
export const sol = (sol) => {
    return lamports(sol * LAMPORTS_PER_SOL);
};
export const usd = (usd) => {
    return amount(usd * 100, USD);
};
export const token = (amount, decimals = 0, symbol = 'Token') => {
    if (typeof amount !== 'number') {
        amount = toBigNumber(amount).toNumber();
    }
    return {
        basisPoints: toBigNumber(amount * Math.pow(10, decimals)),
        currency: {
            symbol,
            decimals,
            namespace: 'spl-token',
        },
    };
};
export const isSol = (currencyOrAmount) => {
    return sameCurrencies(currencyOrAmount, SOL);
};
export const sameAmounts = (left, right) => {
    return sameCurrencies(left, right) && left.basisPoints.eq(right.basisPoints);
};
export const sameCurrencies = (left, right) => {
    if ('currency' in left) {
        left = left.currency;
    }
    if ('currency' in right) {
        right = right.currency;
    }
    return (left.symbol === right.symbol &&
        left.decimals === right.decimals &&
        left.namespace === right.namespace);
};
export function assertCurrency(actual, expected) {
    if ('currency' in actual) {
        actual = actual.currency;
    }
    if (!sameCurrencies(actual, expected)) {
        throw new UnexpectedCurrencyError(actual, expected);
    }
}
export function assertSol(actual) {
    assertCurrency(actual, SOL);
}
export function assertSameCurrencies(left, right, operation) {
    if ('currency' in left) {
        left = left.currency;
    }
    if ('currency' in right) {
        right = right.currency;
    }
    if (!sameCurrencies(left, right)) {
        throw new CurrencyMismatchError(left, right, operation);
    }
}
export const addAmounts = (left, right) => {
    assertSameCurrencies(left, right, 'add');
    return amount(left.basisPoints.add(right.basisPoints), left.currency);
};
export const subtractAmounts = (left, right) => {
    assertSameCurrencies(left, right, 'subtract');
    return amount(left.basisPoints.sub(right.basisPoints), left.currency);
};
export const multiplyAmount = (left, multiplier) => {
    return amount(left.basisPoints.muln(multiplier), left.currency);
};
export const divideAmount = (left, divisor) => {
    return amount(left.basisPoints.divn(divisor), left.currency);
};
export const absoluteAmount = (value) => {
    return amount(value.basisPoints.abs(), value.currency);
};
export const compareAmounts = (left, right) => {
    assertSameCurrencies(left, right, 'compare');
    return left.basisPoints.cmp(right.basisPoints);
};
export const isEqualToAmount = (left, right, tolerance) => {
    tolerance = tolerance !== null && tolerance !== void 0 ? tolerance : amount(0, left.currency);
    assertSameCurrencies(left, right, 'isEqualToAmount');
    assertSameCurrencies(left, tolerance, 'isEqualToAmount');
    const delta = absoluteAmount(subtractAmounts(left, right));
    return isLessThanOrEqualToAmount(delta, tolerance);
};
export const isLessThanAmount = (left, right) => compareAmounts(left, right) < 0;
export const isLessThanOrEqualToAmount = (left, right) => compareAmounts(left, right) <= 0;
export const isGreaterThanAmount = (left, right) => compareAmounts(left, right) > 0;
export const isGreaterThanOrEqualToAmount = (left, right) => compareAmounts(left, right) >= 0;
export const isZeroAmount = (value) => compareAmounts(value, amount(0, value.currency)) === 0;
export const isPositiveAmount = (value) => compareAmounts(value, amount(0, value.currency)) >= 0;
export const isNegativeAmount = (value) => compareAmounts(value, amount(0, value.currency)) < 0;
export const formatAmount = (value) => {
    if (value.currency.decimals === 0) {
        return `${value.currency.symbol} ${value.basisPoints.toString()}`;
    }
    const power = new BN(10).pow(new BN(value.currency.decimals));
    const basisPoints = value.basisPoints;
    const { div, mod } = basisPoints.divmod(power);
    const units = `${div.toString()}.${mod
        .abs()
        .toString(10, value.currency.decimals)}`;
    return `${value.currency.symbol} ${units}`;
};
//# sourceMappingURL=Amount.js.map