import { Ok } from '@hazae41/result';
import { Awaitable } from '../../libs/awaitable/index.js';
import { Option } from './option.js';

interface SomeInit<T> {
    readonly inner: T;
}
declare class Some<T> {
    readonly inner: T;
    /**
     * An existing value
     * @param inner
     */
    constructor(inner: T);
    static create<T>(inner: T): Some<T>;
    static from<T>(init: SomeInit<T>): Some<T>;
    /**
     * Returns an iterator over the possibly contained value
     * @yields `this.inner` if `Some`
     */
    [Symbol.iterator](): Iterator<T, void>;
    /**
     * Type guard for `Some`
     * @returns `true` if `Some`, `false` if `None`
     */
    isSome(): this is Some<T>;
    /**
     * Returns `true` if the option is a `Some` and the value inside of it matches a predicate
     * @param somePredicate
     * @returns `true` if `Some` and `await somePredicate(this.inner)`, `None` otherwise
     */
    isSomeAnd(somePredicate: (inner: T) => Awaitable<boolean>): Promise<boolean>;
    /**
     * Returns `true` if the option is a `Some` and the value inside of it matches a predicate
     * @param somePredicate
     * @returns `true` if `Some` and `somePredicate(this.inner)`, `None` otherwise
     */
    isSomeAndSync(somePredicate: (inner: T) => boolean): boolean;
    /**
     * Type guard for `None`
     * @returns `true` if `None`, `false` if `Some`
     */
    isNone(): false;
    /**
     * Compile-time safely get `this.inner`
     * @returns `this.inner`
     */
    get(): T;
    /**
     * Get the inner value or throw an error
     * @returns
     */
    getOrThrow(): T;
    /**
     * Get the inner value or `null`
     * @returns
     */
    getOrNull(): T;
    /**
     * Get the inner value or a default one
     * @param value
     * @returns `this.inner` if `Some`, `value` if `None`
     */
    getOr(value: unknown): T;
    /**
     * Returns the contained `Some` value or computes it from a closure
     * @param noneCallback
     * @returns `this.inner` if `Some`, `await noneCallback()` if `None`
     */
    getOrElse(noneCallback: unknown): Promise<T>;
    /**
     * Returns the contained `Some` value or computes it from a closure
     * @param noneCallback
     * @returns `this.inner` if `Some`, `noneCallback()` if `None`
     */
    getOrElseSync(noneCallback: unknown): T;
    /**
     * Transform `Option<T>` into `Result<T, NoneError>`
     * @returns `Ok(this.inner)` if `Some`, `Err(NoneError)` if `None`
     */
    ok(): Ok<T>;
    /**
     * Transform `Option<T>` into `Result<T, E>`
     * @param error
     * @returns `Ok(this.inner)` if `Some`, `Err(error)` if `None`
     */
    okOr(error: unknown): Ok<T>;
    /**
     * Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`
     * @param noneCallback
     * @returns `Ok(this.inner)` if `Some`, `Err(await noneCallback())` is `None`
     */
    okOrElse(noneCallback: unknown): Promise<Ok<T>>;
    /**
     * Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`
     * @param noneCallback
     * @returns `Ok(this.inner)` if `Some`, `Err(noneCallback())` is `None`
     */
    okOrElseSync(noneCallback: unknown): Ok<T>;
    /**
     * Returns `None` if the option is `None`, otherwise calls `somePredicate` with the wrapped value
     * @param somePredicate
     * @returns `Some` if `Some` and `await somePredicate(this.inner)`, `None` otherwise
     */
    filter(somePredicate: (inner: T) => Awaitable<boolean>): Promise<Option<T>>;
    /**
     * Returns `None` if the option is `None`, otherwise calls `somePredicate` with the wrapped value
     * @param somePredicate
     * @returns `Some` if `Some` and `somePredicate(this.inner)`, `None` otherwise
     */
    filterSync(somePredicate: (inner: T) => boolean): Option<T>;
    /**
     * Transform `Option<Promise<T>>` into `Promise<Option<T>>`
     * @returns `Promise<Option<T>>`
     */
    await(): Promise<Some<Awaited<T>>>;
    /**
     * Returns `true` if the option is a `Some` value containing the given value
     * @param value
     * @returns `true` if `Some` and `this.inner === value`, `None` otherwise
     */
    contains(value: T): boolean;
    /**
     * Calls the given callback with the inner value if `Ok`
     * @param someCallback
     * @returns `this`
     */
    inspect(someCallback: (inner: T) => Awaitable<void>): Promise<this>;
    /**
     * Calls the given callback with the inner value if `Ok`
     * @param someCallback
     * @returns `this`
     */
    inspectSync(someCallback: (inner: T) => void): this;
    /**
     * Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`)
     * @param someMapper
     * @returns `Some(await someMapper(this.inner))` if `Some`, `this` if `None`
     */
    map<U>(someMapper: (inner: T) => Awaitable<U>): Promise<Some<U>>;
    /**
     * Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`)
     * @param someMapper
     * @returns `Some(someMapper(this.inner))` if `Some`, `this` if `None`
     */
    mapSync<U>(someMapper: (inner: T) => U): Some<U>;
    /**
     * Returns the provided default result (if none), or applies a function to the contained value (if any)
     * @param value
     * @param someMapper
     * @returns `value` if `None`, `await someMapper(this.inner)` if `Some`
     */
    mapOr<U>(value: U, someMapper: (inner: T) => Awaitable<U>): Promise<U>;
    /**
     * Returns the provided default result (if none), or applies a function to the contained value (if any)
     * @param value
     * @param someMapper
     * @returns `value` if `None`, `someMapper(this.inner)` if `Some`
     */
    mapOrSync<U>(value: U, someMapper: (inner: T) => U): U;
    /**
     * Computes a default function result (if none), or applies a different function to the contained value (if any)
     * @param noneCallback
     * @param someMapper
     * @returns `await someMapper(this.inner)` if `Some`, `await noneCallback()` if `None`
     */
    mapOrElse<U>(noneCallback: unknown, someMapper: (inner: T) => Awaitable<U>): Promise<U>;
    /**
     * Computes a default function result (if none), or applies a different function to the contained value (if any)
     * @param noneCallback
     * @param someMapper
     * @returns `someMapper(this.inner)` if `Some`, `noneCallback()` if `None`
     */
    mapOrElseSync<U>(noneCallback: unknown, someMapper: (inner: T) => U): U;
    /**
     * Returns `None` if the option is `None`, otherwise returns `value`
     * @param value
     * @returns `None` if `None`, `value` if `Some`
     */
    and<U>(value: U): U;
    /**
     * Returns `None` if the option is `None`, otherwise calls `someMapper` with the wrapped value and returns the result
     * @param someMapper
     * @returns `None` if `None`, `await someMapper(this.inner)` if `Some`
     */
    andThen<U>(someMapper: (inner: T) => Awaitable<U>): Promise<U>;
    /**
     * Returns `None` if the option is `None`, otherwise calls `someMapper` with the wrapped value and returns the result
     * @param someMapper
     * @returns `None` if `None`, `someMapper(this.inner)` if `Some`
     */
    andThenSync<U>(someMapper: (inner: T) => U): U;
    /**
     * Returns `this` if `Some`, otherwise returns `value`
     * @param value
     * @returns `this` if `Some`, `value` if `None`
     */
    or(value: unknown): this;
    /**
     * Returns `this` if `Some`, otherwise calls `noneCallback` and returns the result
     * @param noneCallback
     * @returns `this` if `Some`, `await noneCallback()` if `None`
     */
    orElse(noneCallback: unknown): Promise<this>;
    /**
     * Returns `this` if `Some`, otherwise calls `noneCallback` and returns the result
     * @param noneCallback
     * @returns `this` if `Some`, `noneCallback()` if `None`
     */
    orElseSync(noneCallback: unknown): this;
    /**
     * Returns `Some` if exactly one of the options is `Some`, otherwise returns `None`
     * @param value
     * @returns `None` if both are `Some` or both are `None`, the only `Some` otherwise
     */
    xor<U>(value: Option<U>): Option<T>;
    /**
     * Zips `this` with another `Option`
     * @param other
     * @returns `Some([this.inner, other.inner])` if both are `Some`, `None` if one of them is `None`
     */
    zip<U>(other: Option<U>): Option<[T, U]>;
}

export { Some, type SomeInit };
