/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */

export type ValidationResult<T> = { success: true, value: T } | { success: false, message: string }

export interface IValidator<T> {
    go(value: unknown, key?: string) : ValidationResult<T>;
}

type ResultCallback<T> = <T>(value: unknown, key?: string) => ValidationResult<T> | IValidator<any> | boolean;
export type PropertyValidator<T> = IValidator<T> | ResultCallback<T>;

/**
 * Takes the <T> type and requires all of its properties to be a PropertyValidator.
 */
export type Shape<T extends object> = Record<keyof T, PropertyValidator<any>>;



export function isValidator<T>(value: unknown): value is IValidator<T> {
    // Check if the value has a .go function. If so, it's an IValidator
    return typeof (value as IValidator<T>).go === "function";
}

export function hasOwnProperty<X extends {}, Y extends PropertyKey>(obj: X, prop: Y) : obj is X & Record<Y, unknown> {
    return obj.hasOwnProperty(prop);
}

export function isString<X extends string>(val: unknown) : val is X {
    return typeof val === 'string';
}

export function isBoolean<X extends boolean>(val: unknown) : val is X {
    return typeof val === 'boolean';
}

export function isNumber<X extends number>(val: unknown) : val is X {
    return typeof val === 'number';
}
