import { telemetry } from '../Telemetry'; /** */
/** @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported. */
export function measure<T>(op: string, a: () => T): T {
    const start = performance.now();
    const ret = a();
    const end = performance.now();
    telemetry.trackTrace({ message: `${op} ${(end - start).toFixed(4)} ms` });
    return ret;
}

export function measureAsync<T, P extends Promise<T>>(op: string, a: () => P): P {
    const start = performance.now();
    const ret = a();
    ret.finally(() => {
        const end = performance.now();
        telemetry.trackTrace({ message: `${op} ${(end - start).toFixed(4)} ms` });
    });

    return ret;
}

export interface StopWatchDeadlineOptions {
    deadline: number;
}

export class StopWatch {
    private _totalElapsed = 0;
    private _start = 0;

    public constructor(start = false) {
        if (start) this.resetAndStart();
    }

    public get isRunning(): boolean {
        return this._start > 0;
    }

    public resetAndStart(): void {
        this._totalElapsed = 0;
        this._start = performance.now();
    }

    public resetAndStop(): void {
        this._start = 0;
        this._totalElapsed = 0;
    }

    public resume(): void {
        if (!this.isRunning) {
            this._start = performance.now();
        }
    }

    public get elapsed(): number {
        return this.isRunning ? performance.now() - this._start : 0;
    }

    public get totalElapsed(): number {
        return this._totalElapsed + this.elapsed;
    }

    public stop(): number {
        if (!this.isRunning) {
            return this._totalElapsed;
        }
        const e = performance.now() - this._start;
        this._totalElapsed += e;
        this._start = 0;
        return e;
    }
}

const resolvedPromise = Promise.resolve();
export function timeoutAsync(ms?: number): Promise<void> {
    if (!ms) {
        // Becomes a microtask. so code afterwards will execute first.
        return resolvedPromise;
    }
    return new Promise<void>((resolve) => {
        setTimeout(() => {
            resolve(undefined);
        }, ms);
    });
}

export function yieldThreadFor(ms?: number): Promise<void> {
    return timeoutAsync(ms);
}
