/* eslint-disable no-cond-assign */
/* eslint-disable ts/no-this-alias */
/* eslint-disable style/no-mixed-operators */
/* eslint-disable eqeqeq */

/* eslint-disable style/max-statements-per-line */
/* eslint-disable unicorn/no-new-array */
/* eslint-disable vars-on-top */
/* eslint-disable no-var */
/* eslint-disable import/no-mutable-exports */
var DP = 20 // 0 to MAX_DP
var RM = 1 // 0, 1, 2 or 3
var MAX_DP = 1e6 // 0 to 1000000
var MAX_POWER = 1e6 // 1 to 1000000
var NE = -7 // 0 to -1000000
var PE = 21 // 0 to 1000000
var STRICT = false // true or false

/**************************************************************************************************/

// Error messages.
var NAME = '[big.js] '
var INVALID = `${NAME}Invalid `
var INVALID_DP = `${INVALID}decimal places`
var INVALID_RM = `${INVALID}rounding mode`
var DIV_BY_ZERO = `${NAME}Division by zero`

// The shared prototype object.
var P = {}
var UNDEFINED = void 0
var NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i
function _Big_() {
  function Big(n) {
    var x = this

    // Enable constructor usage without new.
    if (!(x instanceof Big))
      return n === UNDEFINED ? _Big_() : new Big(n)

    // Duplicate.
    if (n instanceof Big) {
      x.s = n.s
      x.e = n.e
      x.c = n.c.slice()
    }
    else {
      if (typeof n !== 'string') {
        if (Big.strict === true && typeof n !== 'bigint')
          throw new TypeError(`${INVALID}value`)

        // Minus zero?
        n = n === 0 && 1 / n < 0 ? '-0' : String(n)
      }

      parse(x, n)
    }

    // Retain a reference to this Big constructor.
    // Shadow Big.prototype.constructor which points to Object.
    x.constructor = Big
  }

  Big.prototype = P
  Big.DP = DP
  Big.RM = RM
  Big.NE = NE
  Big.PE = PE
  Big.strict = STRICT
  Big.roundDown = 0
  Big.roundHalfUp = 1
  Big.roundHalfEven = 2
  Big.roundUp = 3

  return Big
}
function parse(x, n) {
  var e, i, nl

  if (!NUMERIC.test(n))
    throw new Error(`${INVALID}number`)

  // Determine sign.
  x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1

  // Decimal point?
  if ((e = n.indexOf('.')) > -1)
    n = n.replace('.', '')

  // Exponential form?
  if ((i = n.search(/e/i)) > 0) {
    // Determine exponent.
    if (e < 0)
      e = i
    e += +n.slice(i + 1)
    n = n.substring(0, i)
  }
  else if (e < 0) {
    // Integer.
    e = n.length
  }

  nl = n.length

  // Determine leading zeros.
  for (i = 0; i < nl && n.charAt(i) == '0';) ++i

  if (i == nl) {
    // Zero.
    x.c = [x.e = 0]
  }
  else {
    // Determine trailing zeros.
    for (; nl > 0 && n.charAt(--nl) == '0';);
    x.e = e - i - 1
    x.c = []

    // Convert string to array of digits without leading/trailing zeros.
    for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++)
  }

  return x
}
function round(x, sd, rm, more) {
  var xc = x.c

  if (rm === UNDEFINED)
    rm = x.constructor.RM
  if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3)
    throw new Error(INVALID_RM)

  if (sd < 1) {
    more
      = rm === 3 && (more || !!xc[0]) || sd === 0 && (
        rm === 1 && xc[0] >= 5
        || rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED))
      )

    xc.length = 1

    if (more) {
      // 1, 0.1, 0.01, 0.001, 0.0001 etc.
      x.e = x.e - sd + 1
      xc[0] = 1
    }
    else {
      // Zero.
      xc[0] = x.e = 0
    }
  }
  else if (sd < xc.length) {
    // xc[sd] is the digit after the digit that may be rounded up.
    more
      = rm === 1 && xc[sd] >= 5
      || rm === 2 && (xc[sd] > 5 || xc[sd] === 5
      && (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1))
      || rm === 3 && (more || !!xc[0])

    // Remove any digits after the required precision.
    xc.length = sd

    // Round up?
    if (more) {
      // Rounding up may mean the previous digit has to be rounded up.
      for (; ++xc[--sd] > 9;) {
        xc[sd] = 0
        if (sd === 0) {
          ++x.e
          xc.unshift(1)
          break
        }
      }
    }

    // Remove trailing zeros.
    for (sd = xc.length; !xc[--sd];) xc.pop()
  }

  return x
}
function stringify(x, doExponential, isNonzero) {
  var e = x.e
  var s = x.c.join('')
  var n = s.length

  // Exponential notation?
  if (doExponential) {
    s = s.charAt(0) + (n > 1 ? `.${s.slice(1)}` : '') + (e < 0 ? 'e' : 'e+') + e

  // Normal notation.
  }
  else if (e < 0) {
    for (; ++e;) s = `0${s}`
    s = `0.${s}`
  }
  else if (e > 0) {
    if (++e > n)
      for (e -= n; e--;) s += '0'
    else if (e < n)
      s = `${s.slice(0, e)}.${s.slice(e)}`
  }
  else if (n > 1) {
    s = `${s.charAt(0)}.${s.slice(1)}`
  }

  return x.s < 0 && isNonzero ? `-${s}` : s
}
P.abs = function () {
  var x = new this.constructor(this)
  x.s = 1
  return x
}
P.cmp = function (y) {
  var isneg
  var x = this
  var xc = x.c
  var yc = (y = new x.constructor(y)).c
  var i = x.s
  var j = y.s
  var k = x.e
  var l = y.e

  // Either zero?
  if (!xc[0] || !yc[0])
    return !xc[0] ? !yc[0] ? 0 : -j : i

  // Signs differ?
  if (i != j)
    return i

  isneg = i < 0

  // Compare exponents.
  if (k != l)
    return k > l ^ isneg ? 1 : -1

  j = (k = xc.length) < (l = yc.length) ? k : l

  // Compare digit by digit.
  for (i = -1; ++i < j;) {
    if (xc[i] != yc[i])
      return xc[i] > yc[i] ^ isneg ? 1 : -1
  }

  // Compare lengths.
  return k == l ? 0 : k > l ^ isneg ? 1 : -1
}
P.div = function (y) {
  var x = this
  var Big = x.constructor
  var a = x.c // dividend
  var b = (y = new Big(y)).c // divisor
  var k = x.s == y.s ? 1 : -1
  var dp = Big.DP

  if (dp !== ~~dp || dp < 0 || dp > MAX_DP)
    throw new Error(INVALID_DP)

  // Divisor is zero?
  if (!b[0])
    throw new Error(DIV_BY_ZERO)

  // Dividend is 0? Return +-0.
  if (!a[0]) {
    y.s = k
    y.c = [y.e = 0]
    return y
  }

  var bl; var bt; var n; var cmp; var ri
  var bz = b.slice()
  var ai = bl = b.length
  var al = a.length
  var r = a.slice(0, bl) // remainder
  var rl = r.length
  var q = y // quotient
  var qc = q.c = []
  var qi = 0
  var p = dp + (q.e = x.e - y.e) + 1 // precision of the result

  q.s = k
  k = p < 0 ? 0 : p

  // Create version of divisor with leading zero.
  bz.unshift(0)

  // Add zeros to make remainder as long as divisor.
  for (; rl++ < bl;) r.push(0)

  do {
    // n is how many times the divisor goes into current remainder.
    for (n = 0; n < 10; n++) {
      // Compare divisor and remainder.
      if (bl != (rl = r.length)) {
        cmp = bl > rl ? 1 : -1
      }
      else {
        for (ri = -1, cmp = 0; ++ri < bl;) {
          if (b[ri] != r[ri]) {
            cmp = b[ri] > r[ri] ? 1 : -1
            break
          }
        }
      }

      // If divisor < remainder, subtract divisor from remainder.
      if (cmp < 0) {
        // Remainder can't be more than 1 digit longer than divisor.
        // Equalise lengths using divisor with extra leading zero?
        for (bt = rl == bl ? b : bz; rl;) {
          if (r[--rl] < bt[rl]) {
            ri = rl
            for (; ri && !r[--ri];) r[ri] = 9
            --r[ri]
            r[rl] += 10
          }
          r[rl] -= bt[rl]
        }

        for (; !r[0];) r.shift()
      }
      else {
        break
      }
    }

    // Add the digit n to the result array.
    qc[qi++] = cmp ? n : ++n

    // Update the remainder.
    if (r[0] && cmp)
      r[rl] = a[ai] || 0
    else r = [a[ai]]
  } while ((ai++ < al || r[0] !== UNDEFINED) && k--)

  // Leading zero? Do not remove if result is simply zero (qi == 1).
  if (!qc[0] && qi != 1) {
    // There can't be more than one zero.
    qc.shift()
    q.e--
    p--
  }

  // Round?
  if (qi > p)
    round(q, p, Big.RM, r[0] !== UNDEFINED)

  return q
}
P.eq = function (y) {
  return this.cmp(y) === 0
}
P.gt = function (y) {
  return this.cmp(y) > 0
}
P.gte = function (y) {
  return this.cmp(y) > -1
}
P.lt = function (y) {
  return this.cmp(y) < 0
}
P.lte = function (y) {
  return this.cmp(y) < 1
}
P.minus = P.sub = function (y) {
  var i; var j; var t; var xlty
  var x = this
  var Big = x.constructor
  var a = x.s
  var b = (y = new Big(y)).s
  if (a != b) {
    y.s = -b
    return x.plus(y)
  }
  var xc = x.c.slice()
  var xe = x.e
  var yc = y.c
  var ye = y.e
  if (!xc[0] || !yc[0]) {
    if (yc[0])
      y.s = -b
    else if (xc[0])
      y = new Big(x)
    else
      y.s = 1

    return y
  }
  if (a = xe - ye) {
    if (xlty = a < 0) {
      a = -a
      t = xc
    }
    else {
      ye = xe
      t = yc
    }

    t.reverse()
    for (b = a; b--;) t.push(0)
    t.reverse()
  }
  else {
    j = ((xlty = xc.length < yc.length) ? xc : yc).length
    for (a = b = 0; b < j; b++) {
      if (xc[b] != yc[b]) {
        xlty = xc[b] < yc[b]
        break
      }
    }
  }
  if (xlty) {
    t = xc
    xc = yc
    yc = t
    y.s = -y.s
  }
  if ((b = (j = yc.length) - (i = xc.length)) > 0)
    for (; b--;) xc[i++] = 0
  for (b = i; j > a;) {
    if (xc[--j] < yc[j]) {
      for (i = j; i && !xc[--i];) xc[i] = 9
      --xc[i]
      xc[j] += 10
    }

    xc[j] -= yc[j]
  }
  for (; xc[--b] === 0;) xc.pop()
  for (; xc[0] === 0;) {
    xc.shift()
    --ye
  }

  if (!xc[0]) {
    y.s = 1
    xc = [ye = 0]
  }
  y.c = xc
  y.e = ye
  return y
}
P.mod = function (y) {
  var ygtx
  var x = this
  var Big = x.constructor
  var a = x.s
  var b = (y = new Big(y)).s

  if (!y.c[0])
    throw new Error(DIV_BY_ZERO)

  x.s = y.s = 1
  ygtx = y.cmp(x) == 1
  x.s = a
  y.s = b
  if (ygtx)
    return new Big(x)
  a = Big.DP
  b = Big.RM
  Big.DP = Big.RM = 0
  x = x.div(y)
  Big.DP = a
  Big.RM = b
  return this.minus(x.times(y))
}
P.neg = function () {
  var x = new this.constructor(this)
  x.s = -x.s
  return x
}
P.plus = P.add = function (y) {
  var e; var k; var t
  var x = this
  var Big = x.constructor

  y = new Big(y)
  if (x.s != y.s) {
    y.s = -y.s
    return x.minus(y)
  }
  var xe = x.e
  var xc = x.c
  var ye = y.e
  var yc = y.c
  if (!xc[0] || !yc[0]) {
    if (!yc[0]) {
      if (xc[0])
        y = new Big(x)
      else
        y.s = x.s
    }
    return y
  }
  xc = xc.slice()
  if (e = xe - ye) {
    if (e > 0) {
      ye = xe
      t = yc
    }
    else {
      e = -e
      t = xc
    }
    t.reverse()
    for (; e--;) t.push(0)
    t.reverse()
  }
  if (xc.length - yc.length < 0) {
    t = yc
    yc = xc
    xc = t
  }
  e = yc.length
  for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0
  if (k) {
    xc.unshift(k)
    ++ye
  }
  for (e = xc.length; xc[--e] === 0;) xc.pop()
  y.c = xc
  y.e = ye

  return y
}
P.pow = function (n) {
  var x = this
  var one = new x.constructor('1')
  var y = one
  var isneg = n < 0
  if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER)
    throw new Error(`${INVALID}exponent`)

  if (isneg)
    n = -n
  for (;;) {
    if (n & 1)
      y = y.times(x)
    n >>= 1
    if (!n)
      break
    x = x.times(x)
  }
  return isneg ? one.div(y) : y
}
P.prec = function (sd, rm) {
  if (sd !== ~~sd || sd < 1 || sd > MAX_DP)
    throw new Error(`${INVALID}precision`)

  return round(new this.constructor(this), sd, rm)
}
P.round = function (dp, rm) {
  if (dp === UNDEFINED)
    dp = 0
  else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP)
    throw new Error(INVALID_DP)

  return round(new this.constructor(this), dp + this.e + 1, rm)
}
P.sqrt = function () {
  var r; var c; var t
  var x = this
  var Big = x.constructor
  var s = x.s
  var e = x.e
  var half = new Big('0.5')
  if (!x.c[0])
    return new Big(x)
  if (s < 0)
    throw new Error(`${NAME}No square root`)

  s = Math.sqrt(`${x}`)
  if (s === 0 || s === 1 / 0) {
    c = x.c.join('')
    if (!(c.length + e & 1))
      c += '0'
    s = Math.sqrt(c)
    e = ((e + 1) / 2 | 0) - (e < 0 || e & 1)
    r = new Big((s == 1 / 0 ? '5e' : (s = s.toExponential()).slice(0, s.indexOf('e') + 1)) + e)
  }
  else {
    r = new Big(`${s}`)
  }
  e = r.e + (Big.DP += 4)
  do {
    t = r
    r = half.times(t.plus(x.div(t)))
  } while (t.c.slice(0, e).join('') !== r.c.slice(0, e).join(''))
  return round(r, (Big.DP -= 4) + r.e + 1, Big.RM)
}
P.times = P.mul = function (y) {
  var c
  var x = this
  var Big = x.constructor
  var xc = x.c
  var yc = (y = new Big(y)).c
  var a = xc.length
  var b = yc.length
  var i = x.e
  var j = y.e
  y.s = x.s == y.s ? 1 : -1
  if (!xc[0] || !yc[0]) {
    y.c = [y.e = 0]
    return y
  }
  y.e = i + j
  if (a < b) {
    c = xc
    xc = yc
    yc = c
    j = a
    a = b
    b = j
  }
  for (c = new Array(j = a + b); j--;) c[j] = 0
  for (i = b; i--;) {
    b = 0
    for (j = a + i; j > i;) {
      b = c[j] + yc[i] * xc[j - i - 1] + b
      c[j--] = b % 10
      b = b / 10 | 0
    }
    c[j] = b
  }
  if (b)
    ++y.e
  else c.shift()
  for (i = c.length; !c[--i];) c.pop()
  y.c = c
  return y
}
P.toExponential = function (dp, rm) {
  var x = this
  var n = x.c[0]

  if (dp !== UNDEFINED) {
    if (dp !== ~~dp || dp < 0 || dp > MAX_DP)
      throw new Error(INVALID_DP)

    x = round(new x.constructor(x), ++dp, rm)
    for (; x.c.length < dp;) x.c.push(0)
  }

  return stringify(x, true, !!n)
}
P.toFixed = function (dp, rm) {
  var x = this
  var n = x.c[0]

  if (dp !== UNDEFINED) {
    if (dp !== ~~dp || dp < 0 || dp > MAX_DP)
      throw new Error(INVALID_DP)

    x = round(new x.constructor(x), dp + x.e + 1, rm)

    // x.e may have changed if the value is rounded up.
    for (dp = dp + x.e + 1; x.c.length < dp;) x.c.push(0)
  }

  return stringify(x, false, !!n)
}
P[Symbol.for('nodejs.util.inspect.custom')] = P.toJSON = P.toString = function () {
  var x = this
  var Big = x.constructor
  return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0])
}
P.toNumber = function () {
  var n = Number(stringify(this, true, true))
  if (this.constructor.strict === true && !this.eq(n.toString()))
    throw new Error(`${NAME}Imprecise conversion`)

  return n
}
P.toPrecision = function (sd, rm) {
  var x = this
  var Big = x.constructor
  var n = x.c[0]
  if (sd !== UNDEFINED) {
    if (sd !== ~~sd || sd < 1 || sd > MAX_DP)
      throw new Error(`${INVALID}precision`)

    x = round(new Big(x), sd, rm)
    for (; x.c.length < sd;) x.c.push(0)
  }
  return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n)
}
P.valueOf = function () {
  var x = this
  var Big = x.constructor
  if (Big.strict === true)
    throw new Error(`${NAME}valueOf disallowed`)

  return stringify(x, x.e <= Big.NE || x.e >= Big.PE, true)
}
export var Big = _Big_()
/// <reference types="https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/big.js/index.d.ts" />
export default Big
