// SPDX-License-Identifier: Apache-2.0
import { FixedNumber, parseUnits } from "ethers";
import CheckNums from "../../../core/checks/numbers/CheckNums";
import { Long } from "@hiero-ledger/sdk";
const SEPARATOR = ".";
export default class BigDecimal {
    #fn;
    #decimals;
    get format() {
        return { decimals: this.#decimals };
    }
    get value() {
        return this.#fn.toString();
    }
    get decimals() {
        return this.#decimals;
    }
    static ZERO = BigDecimal.fromString("0", 0);
    static MINUSONE = BigDecimal.fromString("-1", 0);
    constructor(value, format, decimals) {
        const dec = typeof format === "number" ? format : (decimals ?? 0);
        this.#decimals = dec;
        if (typeof value === "string") {
            this.#fn = FixedNumber.fromString(value, dec);
        }
        else {
            this.#fn = FixedNumber.fromValue(value, dec);
        }
    }
    addUnsafe(other) {
        const result = this.#fn.add(other.#fn);
        return BigDecimal.fromString(result.toString(), Math.max(this.#decimals, other.#decimals));
    }
    subUnsafe(other) {
        const result = this.#fn.sub(other.#fn);
        return BigDecimal.fromString(result.toString(), Math.max(this.#decimals, other.#decimals));
    }
    mulUnsafe(other) {
        const result = this.#fn.mul(other.#fn);
        return BigDecimal.fromString(result.toString(), Math.max(this.#decimals, other.#decimals));
    }
    divUnsafe(other) {
        const result = this.#fn.div(other.#fn);
        return BigDecimal.fromString(result.toString(), Math.max(this.#decimals, other.#decimals));
    }
    floor() {
        const result = this.#fn.floor();
        return BigDecimal.fromString(result.toString(), this.#decimals);
    }
    ceiling() {
        const result = this.#fn.ceiling();
        return BigDecimal.fromString(result.toString(), this.#decimals);
    }
    round(decimals) {
        const result = this.#fn.round(decimals ?? 0);
        return BigDecimal.fromString(result.toString(), decimals ?? this.#decimals);
    }
    isZero() {
        return this.#fn.isZero();
    }
    isNegative() {
        return this.#fn.isNegative();
    }
    toUnsafeFloat() {
        return this.#fn.toUnsafeFloat();
    }
    isGreaterOrEqualThan(other) {
        return this.#fn.cmp(other.#fn) >= 0;
    }
    isGreaterThan(other) {
        return this.#fn.cmp(other.#fn) > 0;
    }
    isLowerThan(other) {
        return this.#fn.cmp(other.#fn) < 0;
    }
    isLowerOrEqualThan(other) {
        return this.#fn.cmp(other.#fn) <= 0;
    }
    isEqualThan(other) {
        return this.#fn.cmp(other.#fn) === 0;
    }
    toBigInt() {
        return parseUnits(this.value, this.#decimals);
    }
    toFixedNumber() {
        return this.toBigInt().toString();
    }
    toHexString() {
        const bigIntValue = this.toBigInt();
        return "0x" + bigIntValue.toString(16);
    }
    toString() {
        let number = this.#fn.toString();
        if (number.endsWith(".0")) {
            number = number.substring(0, number.length - 2);
        }
        return number;
    }
    setDecimals(value) {
        // eslint-disable-next-line prefer-const
        let [int, float] = this.value.split(SEPARATOR);
        if (float && float.length && float.length > value) {
            float = float.substring(0, float.length - value);
            return BigDecimal.fromString(`${int}${SEPARATOR}${float}`, Math.max(float?.length ?? 0, value));
        }
        else {
            return BigDecimal.fromString(int, Math.max(0, value));
        }
    }
    splitNumber() {
        const splitNumber = this.#fn.toString().split(".");
        if (splitNumber.length > 1) {
            splitNumber[1] = splitNumber[1].padEnd(this.#decimals, "0");
        }
        else {
            splitNumber[1] = "";
        }
        return splitNumber;
    }
    static getDecimalsFromString(val) {
        if (val.length === 0)
            return 0;
        const [, dec] = val.split(SEPARATOR);
        if (!dec)
            return 0;
        if (!CheckNums.isNumber(dec))
            return 0;
        return dec.replace(/\.0+$/, "").length;
    }
    toLong() {
        const number = this.splitNumber();
        return Long.fromString(number[0] + number[1]);
    }
    static fromString(value, format) {
        if (format === undefined) {
            format = this.getDecimalsFromString(value);
        }
        return new BigDecimal(value, format);
    }
    static fromStringFixed(value, decimals) {
        if (value.length < decimals) {
            value = "0." + value.padStart(decimals - value.length + 1, "0");
        }
        else {
            const position = value.length - decimals;
            value = value.substring(0, position) + "." + value.substring(position);
        }
        return new BigDecimal(value, decimals);
    }
    static fromValue(value, decimals, format) {
        return new BigDecimal(value, format, decimals);
    }
    static isBigDecimal(value) {
        try {
            if (value instanceof BigDecimal)
                return true;
            BigDecimal.fromString(value);
            return true;
        }
        catch (err) {
            return false;
        }
    }
}
