import bundle from './validation.nls';
import { create } from '@dojo/framework/core/vdom';
import i18n from '@dojo/framework/core/middleware/i18n';
const upperCaseRegEx = /[A-Z]/;
const numbersRegEx = /\d/;
/* OWASP Special Characters: https://www.owasp.org/index.php/Password_special_characters */
const specialCharactersRegEx = new RegExp([
    ' ',
    '!',
    '"',
    '#',
    '\\$',
    '%',
    '&',
    "'",
    '\\(',
    '\\)',
    '\\*',
    '\\+',
    ',',
    '-',
    '\\.',
    '/',
    ':',
    ';',
    '<',
    '=',
    '>',
    '\\?',
    '@',
    '\\[',
    '\\\\',
    '\\]',
    '\\^',
    '_',
    '`',
    '{',
    '\\|',
    '}',
    '~'
].join('|'));
const validationFactory = create({ i18n });
const validation = validationFactory(function validation({ middleware: { i18n } }) {
    const { format } = i18n.localize(bundle);
    function formatList(atLeast, list) {
        const fixedList = [...list];
        if (list.length > 1) {
            if (atLeast) {
                fixedList[fixedList.length - 1] = format('or', {
                    rule: fixedList[fixedList.length - 1]
                });
            }
            else {
                fixedList[fixedList.length - 1] = format('and', {
                    rule: fixedList[fixedList.length - 1]
                });
            }
        }
        if (fixedList.length === 1 && !atLeast) {
            return format('mustContain', { rules: fixedList[0] });
        }
        return format('mustContain', {
            rules: format(atLeast ? 'atLeastOf' : 'allOf', {
                count: atLeast,
                rules: fixedList.join(', ')
            })
        });
    }
    const validators = {
        length: {
            validate: ({ min, max }, value) => {
                if (min !== undefined) {
                    if (value.length < min) {
                        return {
                            valid: false,
                            message: format('minimumLength', { length: min })
                        };
                    }
                }
                if (max !== undefined) {
                    if (value.length > max) {
                        return {
                            valid: false,
                            message: format('maximumLength', { length: max })
                        };
                    }
                }
            },
            describe: ({ min, max }) => {
                const limits = [];
                if (min !== undefined) {
                    limits.push(format('minimumLength', { length: min }));
                }
                if (max !== undefined) {
                    limits.push(format('maximumLength', { length: max }));
                }
                return limits;
            }
        },
        contains: {
            validate: ({ atLeast, uppercase = 0, numbers = 0, specialCharacters = 0 }, value) => {
                const failures = [];
                let uppercaseTotal = 0;
                let numberTotal = 0;
                let specialTotal = 0;
                let containsAtLeast = atLeast || 0;
                let successes = 0;
                if (atLeast === undefined) {
                    containsAtLeast =
                        (uppercase ? 1 : 0) + (numbers ? 1 : 0) + (specialCharacters ? 1 : 0);
                }
                for (let i = 0; i < value.length; i++) {
                    const c = value.charAt(i);
                    uppercaseTotal += uppercase && upperCaseRegEx.test(c) ? 1 : 0;
                    numberTotal += numbers && numbersRegEx.test(c) ? 1 : 0;
                    specialTotal += specialCharacters && specialCharactersRegEx.test(value) ? 1 : 0;
                }
                if (uppercaseTotal < uppercase) {
                    failures.push(format('uppercase', {
                        count: uppercase
                    }));
                }
                else if (uppercase) {
                    successes++;
                }
                if (numberTotal < numbers) {
                    failures.push(format('numbers', {
                        count: numbers
                    }));
                }
                else if (numbers) {
                    successes++;
                }
                if (specialTotal < specialCharacters) {
                    failures.push(format('specialCharacters', {
                        count: specialCharacters
                    }));
                }
                else if (specialCharacters) {
                    successes++;
                }
                if (successes < containsAtLeast) {
                    return {
                        valid: false,
                        message: formatList(atLeast ? containsAtLeast - successes : undefined, failures)
                    };
                }
            },
            describe: ({ atLeast, uppercase, numbers, specialCharacters }) => {
                let types = [];
                if (uppercase) {
                    types.push(format('uppercase', {
                        count: uppercase
                    }));
                }
                if (numbers) {
                    types.push(format('numbers', {
                        count: numbers
                    }));
                }
                if (specialCharacters) {
                    types.push(format('specialCharacters', {
                        count: specialCharacters
                    }));
                }
                return [formatList(atLeast, types)];
            }
        }
    };
    return (rules) => {
        function validator(value) {
            const failedResults = Object.keys(rules)
                .map((rule) => validators[rule] && validators[rule].validate(rules[rule], value))
                .filter((result) => result && !result.valid);
            if (failedResults.length) {
                return {
                    valid: false,
                    message: failedResults.map((result) => (result ? result.message : '')).join(' ')
                };
            }
        }
        validator.describe = () => Object.keys(rules).reduce((prev, rule) => [...prev, ...validators[rule].describe(rules[rule])], []);
        return validator;
    };
});
export default validation;

/*# sourceMappingURL=validation.mjs.map*/