export type SBErrorType =
  | 'InvalidLicense'
  | 'NullPointer'
  | 'InvalidArgument'
  | 'InvalidImageRef'
  | 'ComponentUnavailable'
  | 'IllegalState'
  | 'IOError'
  | 'InvalidData'
  | 'OutOfMemory'
  | 'Timeout'
  | 'ProcessError'
  | 'Unknown';

export abstract class SBError extends Error {
  public abstract readonly type: SBErrorType;

  protected constructor(message: string) {
    super(message);
  }
}

export class InvalidLicenseError extends SBError {
  public readonly type: SBErrorType = 'InvalidLicense';

  constructor(message: string) {
    super(message);
  }
}

export class NullPointerError extends SBError {
  public readonly type: SBErrorType = 'NullPointer';

  constructor(message: string) {
    super(message);
  }
}

export class InvalidArgumentError extends SBError {
  public readonly type: SBErrorType = 'InvalidArgument';

  constructor(message: string) {
    super(message);
  }
}

export class InvalidImageRefError extends SBError {
  public readonly type: SBErrorType = 'InvalidImageRef';

  constructor(message: string) {
    super(message);
  }
}

export class ComponentUnavailableError extends SBError {
  public readonly type: SBErrorType = 'ComponentUnavailable';

  constructor(message: string) {
    super(message);
  }
}

export class IllegalStateError extends SBError {
  public readonly type: SBErrorType = 'IllegalState';

  constructor(message: string) {
    super(message);
  }
}

export class IOError extends SBError {
  public readonly type: SBErrorType = 'IOError';

  constructor(message: string) {
    super(message);
  }
}

export class InvalidDataError extends SBError {
  public readonly type: SBErrorType = 'InvalidData';

  constructor(message: string) {
    super(message);
  }
}

export class OutOfMemoryError extends SBError {
  public readonly type: SBErrorType = 'OutOfMemory';

  constructor(message: string) {
    super(message);
  }
}

export class TimeoutError extends SBError {
  public readonly type: SBErrorType = 'Timeout';

  constructor(message: string) {
    super(message);
  }
}

export class UnknownError extends SBError {
  public readonly type: SBErrorType = 'Unknown';

  constructor(message: string) {
    super(message);
  }
}

export class ProcessError extends SBError {
  public readonly type: SBErrorType = 'ProcessError';
  public readonly code: number;

  constructor(message: string, code: number) {
    super(message);
    this.code = code;
  }
}

/**
 * @internal
 * @hidden
 */
export function createSBError(err: any): SBError {
  const code = Number(err.code);
  const message = err.message || err.errorMessage || 'An unknown error occurred';
  switch (code) {
    case 1:
      return new UnknownError(message);
    case 2:
      return new InvalidLicenseError(message);
    case 3:
      return new NullPointerError(message);
    case 4:
      return new InvalidArgumentError(message);
    case 5:
      return new InvalidImageRefError(message);
    case 6:
      return new ComponentUnavailableError(message);
    case 7:
      return new IllegalStateError(message);
    case 8:
      return new IOError(message);
    case 9:
      return new InvalidDataError(message);
    case 11:
      return new OutOfMemoryError(message);
    case 12:
      return new TimeoutError(message);
    default: {
      if (code >= 100) {
        return new ProcessError(message, code);
      }
      return new UnknownError(message);
    }
  }
}
