import { Directive } from 'vue';
import { ValidateRules, Rules } from './interface';

/**
* 表单验证规则
*/
const validateRules: ValidateRules = {
    password: {
        reg: /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$)^.{8,64}$/,
        message: '密码不符合规则',
    },
    phone: {
        reg: /^$|^1[3456789]\d{9}$/,
        message: '手机号码无效',
    },
    email: {
        reg: /^$|^([a-zA-Z]|[0-9])(\w)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
        message: '邮箱地址无效',
    },
    en: {
        reg: /^[A-Za-z]+$/,
        message: '只能输入英文字母（不允许空格）',
    },
    enname: {
        reg: /^[a-zA-Z0-9_]{1,}$/,
        message: '只能输入英文字母、数字、下划线',
    }
}

/**
 * 表单验证
 */
function validateTools(value: string, rules: Rules[]) {
    for (let i = 0; i < rules.length; i++) {
        const { rule, required, type, min, max, message } = rules[i];

        if (required) {
            const reg = /\S/;
            if (!reg.test(value)) {
                return message || '必填项不能为空';
            }
        }

        switch (type) {
            case 'number': {
                const num = Number(value);
                if (isNaN(num)) {
                    return message || '只能输入数值';
                }
                // 验证最小数值
                if (min !== undefined) {
                    if (num < min) {
                        return message || '数值不能小于' + min;
                    }
                }
                // 验证最大数值
                if (max !== undefined) {
                    if (num > max) {
                        return message || '数值不能大于' + max;
                    }
                }
                break;
            }
            default: {
                const strlength = value.length;
                // 验证最小长度
                if (min !== undefined) {
                    if (strlength < min) {
                        return message || '不能少于' + min + '个字符';
                    }
                }
                // 验证最大长度
                if (max !== undefined) {
                    if (strlength > max) {
                        return message || '不能大于' + max + '个字符';
                    }
                }
            }
        }

        //验证规则
        if (rule) {
            const validate = validateRules[rule];
            if (!validate.reg.test(value)) {
                return message || validate.message;
            }
        }
    }

    return 'ok';
}

/**
 * 创建元素
 */
function createElement(el: HTMLElement, content: string | undefined) {
    el.classList.add('validate-error'); // 添加样式
    const errorNode = el.nextSibling as HTMLElement;

    if (content) {
        if (errorNode && errorNode.className === 'validate-message') {
            errorNode.innerHTML = content;
        } else {
            const node = document.createElement('div');
            node.className = 'validate-message';
            node.innerHTML = '<span>' + content + '</span>';

            el.parentNode?.insertBefore(node, errorNode);
        }
    } else {
        removeElement(el);
    }
}

/**
 * 移除元素
 */
function removeElement(el: HTMLElement) {
    el.classList.remove('validate-error'); // 移除样式
    const errorNode = el.nextSibling as HTMLElement;

    if (errorNode && errorNode.className === 'validate-message') {
        errorNode.remove();
    }
}

/**
 * 表单验证指令
 * 参数[binding.arg]：元素的标识名称，默认'default',
 * 修饰符[binding.modifiers]：sync 是否即时显示错误提示，默认false
 * 格式：<input v-rules="[{ rules: 'password', message: 'error message' }]" />
 */
export const rules: Directive = {
    mounted(el, binding) {
        const validateId = binding.arg || 'default';
        const input: HTMLInputElement = el.querySelector('input') || el;
        el.dataset['validate'] = validateId;

        // 监听change事件
        input.addEventListener('change', () => {
            const message = validateTools(input.value, binding.value); // 验证数据
            const button = document.querySelector(`[data-validate-submit='${validateId}']`) as HTMLElement;
            const showErrors = button?.dataset['validateSync'];

            input.dataset['validateMessage'] = message;

            // 是否显示错误提示
            if (binding.modifiers['sync'] || showErrors === 'true') {
                if (message === 'ok') {
                    removeElement(el);
                } else {
                    createElement(el, message);
                }
            } else {
                removeElement(el);
            }
        })
    }
}

/**
 * 表单验证指令
 * 参数[binding.arg]：元素的标识名称，默认'default'
 * 修饰符[binding.modifiers]：sync 是否即时显示错误提示，默认false
 * 格式：<input v-rules="[{ rules: 'password', message: 'error message' }]" />
 */
export const validate: Directive = {
    mounted(el, binding) {
        const validateId = binding.arg || 'default';
        el.dataset['validateSubmit'] = validateId;
        el.dataset['validateSync'] = binding.modifiers['sync'] || false;

        const nodes = document.querySelectorAll(`[data-validate='${validateId}']`),
            inputs = Array.from(nodes).map((e) => {
                const result = e.querySelector('input') || e;
                return result as HTMLInputElement;
            });

        // 绑定onclick事件
        el.onclick = () => {
            const fun = binding.value;
            if (fun) {
                // 创建自定义事件
                const evt = new Event('change', { bubbles: true });
                inputs.forEach((e) => {
                    // 触发自定义事件
                    e.dispatchEvent(evt);
                });

                // 验证失败消息
                const result = inputs.reduce((res, e) => {
                    const message = e.dataset['validateMessage'] || '验证失败';
                    if (message !== 'ok') {
                        res.push(message);
                    }
                    return res;
                }, [] as string[]);

                fun(result);
            }
        }
    }
}