import {validator} from '../vendor';

export const validators = {
    presence: ($translate, value) => {
        if (validator.isEmpty(value ? String(value) : ''))
            throw new Error(_($translate, `Value can't be empty`));
    },
    absence: ($translate, value) => {
        if (!validator.isEmpty(value))
            throw new Error(_($translate, `Value should be empty`));
    },
    length: ($translate, value, conf) => {
        let options = {
            min: conf.min || conf.is,
            max: conf.max || conf.is
        };
        let val = value ? String(value) : '';
        if (!validator.isLength(val, options)) {
            if (conf.is) {
                throw new Error(_($translate,
                    `Value should be %s characters long`, [conf.is]));
            } else if (conf.min && conf.max) {
                throw new Error(_($translate,
                    `Value should have a length between %s and %s`, [conf.min, conf.max]));
            } else if (conf.min) {
                throw new Error(_($translate,
                    `Value should have at least %s characters`, [conf.min]));
            } else {
                throw new Error(_($translate,
                    `Value should have at most %s characters`, [conf.max]));
            }
        }
    },
    numericality: ($translate, value, conf) => {
        if (conf.int) {
            if (!validator.isInt(value))
                throw new Error(_($translate, `Value should be integer`));
        } else if (!validator.isNumeric(value))
            throw new Error(_($translate, `Value should be a number`));
    },
    inclusion: ($translate, value, conf) => {
        if (!validator.isIn(value, conf.in))
            throw new Error(_($translate, `Invalid value`));
    },
    exclusion: ($translate, value, conf) => {
        if (validator.isIn(value, conf.in))
            throw new Error(_($translate, `Invalid value`));
    },
    format: ($translate, value, conf) => {
        if (!validator.matches(value, conf.with))
            throw new Error(_($translate, `Invalid value`));
    },
    custom: ($translate, value, conf) => {
        if (!conf.bindedFunction(value))
            throw new Error(_($translate, `Invalid value`));
    }
};

/**
 * Checks if value satisfies a set of validations.
 *
 * @param {*} value The value
 * @param {Array} validations Array with validations
 */
export function validateAll($translate, value, validations) {
    for (let conf of validations)
        validate($translate, value, conf);
}

/**
 * Checks if value satisfies a validation.
 *
 * @param {*} value The value
 * @param {Object} conf The validation configuration
 */
export function validate($translate, value, conf) {
    let validator = validators[conf.validation];
    try {
        let isEmpty = value == null || value === '';

        if (isEmpty)
            checkNull($translate, value, conf);
        if (validator && (!isEmpty || conf.validation == 'presence'))
            validator($translate, value, conf);
    } catch (e) {
        let message = conf.message ? conf.message : e.message;
        throw new Error(_($translate, message));
    }
}

/**
 * Checks if value satisfies a blank or not null validation.
 *
 * @param {*} value The value
 * @param {Object} conf The validation configuration
 */
export function checkNull($translate, value, conf) {
    if (conf.allowBlank === false && value === '')
        throw new Error(_($translate, `Value can't be blank`));
    else if (conf.allowNull === false && value == null)
        throw new Error(_($translate, `Value can't be null`));
}

export function _($translate, text, params = []) {
    text = $translate.instant(text);

    for (let i = 0; i < params.length; i++) {
        text = text.replace('%s', params[i]);
    }

    return text;
}