import ngModule from '../module';
import {validateAll} from '../lib/validator';
import {firstUpper} from '../lib/string';

directive.$inject = ['$translate', '$window'];
export function directive($translate, $window) {
    return {
        restrict: 'A',
        link: link,
        require: {
            ngModel: 'ngModel',
            form: '^^?form'
        }
    };

    function link($scope, $element, $attrs, $ctrl) {
        let vnValidations = $window.validations;
        if (!vnValidations) return;

        if (!/^([A-Z]\w+(\.[a-z]\w*)?)?$/.test($attrs.rule))
            throw new Error(`rule: Attribute must have this syntax: [ModelName[.fieldName]]`);

        let rule = $attrs.rule.split('.');
        let modelName = rule.shift();
        let fieldName = rule.shift();

        let split = $attrs.ngModel.split('.');
        if (!fieldName) fieldName = split.pop() || null;
        if (!modelName) modelName = firstUpper(split.pop() || '');

        if (!modelName || !fieldName)
            throw new Error(`rule: Cannot retrieve model or field attribute`);

        let modelValidations = vnValidations[modelName];

        if (!modelValidations)
            throw new Error(`rule: Model '${modelName}' doesn't exist`);

        let validations = modelValidations.validations[fieldName];
        if (!validations || validations.length == 0)
            return;

        let ngModel = $ctrl.ngModel;
        let form = $ctrl.form;
        let field = $element[0].$ctrl;
        let error;

        function refreshError() {
            if (!field) return;
            let canShow = ngModel.$dirty || (form && form.$submitted);
            field.error = error && canShow ? error.message : null;
        }

        ngModel.$options.$$options.allowInvalid = true;
        ngModel.$validators.entity = value => {
            try {
                error = null;
                validateAll($translate, value, validations);
            } catch (e) {
                error = e;
            }

            refreshError();
            return error == null;
        };

        if (form)
            $scope.$watch(() => form.$submitted, refreshError);
    }
}
ngModule.directive('rule', directive);