/**
 * Result type for operations that can fail
 * 
 * Inspired by Rust's Result type, this provides a type-safe way to handle
 * success and error cases without exceptions.
 */

export interface ResultOk<T> {
  isOk(): true;
  isErr(): false;
  unwrap(): T;
  unwrapOr(defaultValue: T): T;
  getError(): never;
  map<U>(fn: (value: T) => U): ResultOk<U>;
}

export interface ResultError<E> {
  isOk(): false;
  isErr(): true;
  unwrap(): never;
  unwrapOr<T>(defaultValue: T): T;
  getError(): E;
  map<U>(fn: (value: unknown) => U): ResultError<E>;
}

export class Ok<T> implements ResultOk<T> {
  constructor(private readonly value: T) {}

  isOk(): true { return true; }
  isErr(): false { return false; }
  unwrap(): T { return this.value; }
  unwrapOr(_: T): T { return this.value; }
  getError(): never {
    throw new Error('Cannot get error from Ok result');
  }
  map<U>(fn: (value: T) => U): ResultOk<U> {
    return new Ok(fn(this.value));
  }
}

export class Err<E> implements ResultError<E> {
  constructor(private readonly error: E) {}

  isOk(): false { return false; }
  isErr(): true { return true; }
  unwrap(): never {
    throw new Error(`Called unwrap on error: ${this.error}`);
  }
  unwrapOr<T>(defaultValue: T): T { return defaultValue; }
  getError(): E { return this.error; }
  map<U>(_: (value: unknown) => U): ResultError<E> {
    return this as unknown as ResultError<E>;
  }
}

/**
 * Result type alias
 */
export type Result<T, E> = ResultOk<T> | ResultError<E>;

/**
 * Result class with static factory methods
 * 
 * Usage:
 * - Result.ok(value) creates a successful Result
 * - Result.err(error) creates an error Result
 */
export const Result = {
  ok<T>(value: T): Result<T, never> {
    return new Ok(value);
  },
  
  err<E>(error: E): Result<never, E> {
    return new Err(error);
  },
};
