export function before<F extends (...args: any[]) => any>(
    before: (this: ThisParameterType<F>, ...args: Parameters<F>) => void, target: F
): F {
    return function (this: ThisParameterType<F>, ...args: Parameters<F>): ReturnType<F> {
        before.call(this, ...args);
        return target.apply(this, args);
    } as F;
}

export function around<F extends (...args: any[]) => any>(
    target: F,
    around: (target: F, ...args: Parameters<F>) => ReturnType<F>
): F {
    return function (this: ThisParameterType<F>, ...args: Parameters<F>): ReturnType<F> {
        return around.call(this, target, ...args);
    } as F;
}

export function after<F extends (...args: any[]) => any>(
    target: F,
    after: (this: ThisParameterType<F>, ...args: Parameters<F>) => void
): F {
    return function (this: ThisParameterType<F>, ...args: Parameters<F>): ReturnType<F> {
        let result = target.apply(this, args);
        after.call(this, ...args);
        return result;
    } as F;
}

export function setMinTimeout(beginTime: number | Date, callback: () => void, minTimeout: number = 1500): void {
    if (beginTime instanceof Date) {
        beginTime = beginTime.getTime() as any;
    }
    const dTime = new Date().getTime() - (beginTime as any);
    if (dTime > minTimeout) {
        callback();
    } else {
        setTimeout(callback, minTimeout - dTime);
    }
}

