import bs58 from 'bs58';
import type { BufferParams } from "../common/interfaces";
import BufferUtils from '../utils/buffer.utils';

export default class Base58 {

  private static readonly ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split('');

  private buf?: Uint8Array;

  constructor(obj?: string | Uint8Array | BufferParams) {
    if (BufferUtils.isBuffer(obj)) {
      let buf = obj;
      this.fromBuffer(buf);
    } else if (typeof obj === 'string') {
      let str = obj;
      this.fromString(str);
    } else if (obj) {
      this.set(obj);
    }
  }

  public toBuffer(): Uint8Array | undefined {
    return this.buf;
  }
  
  public toString(): string {
    return this.buf ? Base58.encode(this.buf) : "";
  }

  private fromBuffer(buf: Uint8Array): this {
    this.buf = buf;
    return this;
  }
  
  private fromString(str: string): this {
    let buf = Base58.decode(str);
    this.buf = buf;
    return this;
  }

  private set(obj: BufferParams): this {
    this.buf = obj.buf || this.buf || undefined;
    return this;
  }

  public static encode(buf: Uint8Array): string {
    if (!BufferUtils.isBuffer(buf)) {
      throw new Error('Input should be a buffer');
    }
    return bs58.encode(buf);
  }

  public static decode(str: string): Uint8Array {
    if (typeof str !== 'string') {
      throw new Error('Input should be a string');
    }
    return Uint8Array.from(bs58.decode(str));
  }

  
  public static validCharacters(chars: Uint8Array | string): boolean {
    if (BufferUtils.isBuffer(chars)) {
      chars = BufferUtils.bufferToUtf8(chars);
    }

    return chars.split("").every(char => Base58.ALPHABET.includes(char));
  }
}