"use strict";
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bn_js_1 = __importDefault(require("bn.js"));
const util_1 = require("@polkadot/util");
const util_crypto_1 = require("@polkadot/util-crypto");
const Raw_1 = __importDefault(require("./Raw"));
exports.DEFAULT_UINT_BITS = 64;
/**
 * @name AbstractInt
 * @ignore
 * @noInheritDoc
 */
// TODO:
//   - Apart from encoding/decoding we don't actually keep check on the sizes, is this good enough?
class AbstractInt extends bn_js_1.default {
    constructor(registry, isNegative, value = 0, bitLength = exports.DEFAULT_UINT_BITS, isHexJson = true) {
        super(AbstractInt.decodeAbstracInt(value, bitLength, isNegative));
        this.registry = registry;
        this._bitLength = bitLength;
        this._isHexJson = isHexJson;
        this._isNegative = isNegative;
    }
    /** @internal */
    static decodeAbstracInt(value, bitLength, isNegative) {
        // This function returns a string, which will be passed in the BN
        // constructor. It would be ideal to actually return a BN, but there's a
        // bug: https://github.com/indutny/bn.js/issues/206.
        if (util_1.isHex(value, -1, true)) {
            return util_1.hexToBn(value, { isLe: false, isNegative }).toString();
        }
        else if (util_1.isU8a(value)) {
            return AbstractInt.decodeAbstracIntU8a(value, bitLength, isNegative);
        }
        else if (util_1.isString(value)) {
            return new bn_js_1.default(value, 10).toString();
        }
        return util_1.bnToBn(value).toString();
    }
    /** @internal */
    static decodeAbstracIntU8a(value, bitLength, isNegative) {
        if (!value.length) {
            return '0';
        }
        try {
            // NOTE When passing u8a in (typically from decoded data), it is always Little Endian
            return util_1.u8aToBn(value.subarray(0, bitLength / 8), { isLe: true, isNegative }).toString();
        }
        catch (error) {
            throw new Error(`AbstractInt: failed on ${JSON.stringify(value)}:: ${error.message}`);
        }
    }
    /**
     * @description The length of the value when encoded as a Uint8Array
     */
    get encodedLength() {
        return this._bitLength / 8;
    }
    /**
     * @description returns a hash of the contents
     */
    get hash() {
        return new Raw_1.default(this.registry, util_crypto_1.blake2AsU8a(this.toU8a(), 256));
    }
    /**
     * @description Checks if the value is a zero value (align elsewhere)
     */
    get isEmpty() {
        return this.isZero();
    }
    /**
     * @description Returns the number of bits in the value
     */
    bitLength() {
        return this._bitLength;
    }
    /**
     * @description Compares the value of the input to see if there is a match
     */
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    eq(other) {
        // Here we are actually overriding the built-in .eq to take care of both
        // number and BN inputs (no `.eqn` needed) - numbers will be converted
        return super.eq(util_1.isHex(other)
            ? util_1.hexToBn(other.toString(), { isLe: false, isNegative: this._isNegative })
            : util_1.bnToBn(other));
    }
    /**
     * @description True if this value is the max of the type
     */
    isMax() {
        const u8a = this.toU8a().filter((byte) => byte === 0xff);
        return u8a.length === (this._bitLength / 8);
    }
    /**
     * @description Returns the BN representation of the number. (Compatibility)
     */
    toBn() {
        return this;
    }
    /**
     * @description Converts the Object to JSON, typically used for RPC transfers
     */
    toJSON() {
        // FIXME this return type should by string | number, but BN's return type
        // is string.
        // Maximum allowed integer for JS is 2^53 - 1, set limit at 52
        return this._isHexJson || (super.bitLength() > 52)
            ? this.toHex()
            : this.toNumber();
    }
    /**
     * @description Returns the string representation of the value
     * @param base The base to use for the conversion
     */
    toString(base) {
        // only included here since we do not inherit docs
        return super.toString(base);
    }
}
exports.default = AbstractInt;
