export class Result<T> {
  private constructor(
    private readonly success: boolean,
    private readonly value?: T,
    private readonly error?: string
  ) {}

  static ok<U>(value: U): Result<U> {
    return new Result<U>(true, value);
  }

  static fail<U>(error: string): Result<U> {
    return new Result<U>(false, undefined, error);
  }

  isSuccess(): boolean {
    return this.success;
  }

  isFailure(): boolean {
    return !this.success;
  }

  getValue(): T {
    if (!this.success) {
      throw new Error('Cannot get value from failed result');
    }
    return this.value!;
  }

  getError(): string {
    if (this.success) {
      throw new Error('Cannot get error from successful result');
    }
    return this.error!;
  }

  map<U>(fn: (value: T) => U): Result<U> {
    if (this.isFailure()) {
      return Result.fail<U>(this.error!);
    }
    return Result.ok(fn(this.value!));
  }

  flatMap<U>(fn: (value: T) => Result<U>): Result<U> {
    if (this.isFailure()) {
      return Result.fail<U>(this.error!);
    }
    return fn(this.value!);
  }
}
