import type { PromiseCallbacks } from '../types/callbacks.js';

/** Promise Status */
type PromiseStatus = 'pending' | 'fulfilled' | 'rejected';
/** Ready Promise */
export class ReadyPromise {
    constructor() {
        let resolve: PromiseCallbacks<void>[0], reject: PromiseCallbacks<void>[1];
        const p = new Promise<void>((res, rej) => {
            resolve = res;
            reject = rej;
        });
        p.catch(() => {
            // Avoid unhandled rejection
        });
        this.#value = p;
        this.#resolve = resolve!;
        this.#reject = reject!;
    }

    readonly #value!: Promise<void>;
    readonly #resolve!: () => void;
    readonly #reject!: (reason?: unknown) => void;
    #status: PromiseStatus = 'pending';

    /** Resolve the promise */
    resolve(): void {
        if (this.#status !== 'pending') return;
        this.#status = 'fulfilled';
        this.#resolve();
    }

    /** Reject the promise */
    reject(reason: Error): void {
        if (this.#status !== 'pending') return;
        this.#status = 'rejected';
        this.#reject(reason);
    }

    /** Settle the promise by provided promise */
    settle(p: Promise<void>): void {
        p.then(
            () => this.resolve(),
            (err: Error) => this.reject(err),
        );
    }

    /** Get the status of the promise */
    get status(): PromiseStatus {
        return this.#status;
    }

    /** Check if the promise is settled */
    get settled(): boolean {
        return this.#status !== 'pending';
    }

    /** Get the underlying promise */
    get value(): Promise<void> {
        return this.#value;
    }
}
