export class Snowflake {
  private readonly _epoch: bigint
  private _lastTimestamp: bigint
  private readonly _workerId: bigint
  private _sequence: bigint

  constructor(readonly dataCenterId: number = 0, readonly machineId: number = 0, readonly epoch: bigint = 1730953483570n) {
    if (dataCenterId > 31 || dataCenterId < 0
        || machineId > 31 || machineId < 0) {
      throw new Error('数据中心 Id 和机器 Id的取值应为：0~31')
    }
    if (epoch < 0) {
      throw new Error('时间戳起点应 >=0')
    }
    this._epoch = epoch
    this._lastTimestamp = -1n
    this._workerId = BigInt((dataCenterId << 5) | machineId)
    this._sequence = 0n
  }

  public nextId() {
    let timestamp = BigInt(Date.now())

    if (timestamp < this._lastTimestamp) {
      throw new Error('时钟回拨错误')
    }

    if (timestamp === this._lastTimestamp) {
      this._sequence = (this._sequence + 1n) & 4095n
      if (this._sequence === 0n) {
        timestamp = this.waitForNextMillis()
      }
    } else {
      this._sequence = 0n
    }
    this._lastTimestamp = timestamp
    return ((timestamp - this._epoch) << 22n)
        | (this._workerId << 12n)
        | this._sequence
  }

  private waitForNextMillis() {
    let timestamp = BigInt(Date.now())
    while (timestamp <= this._lastTimestamp) {
      timestamp = BigInt(Date.now())
    }
    return timestamp
  }
}

const snowflake = new Snowflake()

export { snowflake }

export default snowflake
