import ngModule from '../../module';
import FormInput from '../form-input';
import './style.scss';

export default class Field extends FormInput {
    constructor($element, $scope, $transclude) {
        super($element, $scope, $transclude);

        this.prefix = null;
        this.suffix = null;

        this.container = this.element.querySelector('.container');
        this.container.addEventListener('focusout', () => this.onFocus(false));
        this.container.addEventListener('focusin', () => this.onFocus(true));

        this.control = this.element.querySelector('.control');
    }

    $onInit() {
        super.$onInit();

        if (this.info) this.classList.add('has-icons');
        this.element.addEventListener('change', event =>
            this.onChange(event));
    }

    set field(value) {
        if (value === this.field) return;
        super.field = value;
        this.classList.toggle('not-empty', value != null && value !== '');
        this.validateValue();
    }

    get field() {
        return super.field;
    }

    set input(value) {
        if (this.input)
            this.control.removeChild(this.input);
        this._input = value;
        if (value)
            this.control.appendChild(value);
    }

    get input() {
        return this._input;
    }

    set value(value) {
        this.input.value = value;
    }

    get value() {
        return this.input.value;
    }

    set type(value) {
        this.input.type = value;
    }

    get type() {
        return this.input.type;
    }

    set name(value) {
        this.input.name = value;
    }

    get name() {
        return this.input.name;
    }

    set placeholder(value) {
        this.input.placeholder = value;
    }

    get placeholder() {
        return this.input.placeholder;
    }

    set required(value) {
        this._required = value;
        let required = this.element.querySelector('.required');
        display(required, this._required);
    }

    get required() {
        return this._required;
    }

    set prefix(value) {
        this._prefix = value;
        this.refreshFix('.prefix', value);
    }

    get prefix() {
        return this._prefix;
    }

    set suffix(value) {
        this._suffix = value;
        this.refreshFix('.suffix', value);
    }

    get suffix() {
        return this._suffix;
    }

    set hint(value) {
        this._hint = value;
        this.refreshHint();
    }

    get hint() {
        return this._hint;
    }

    set error(value) {
        if (value === this.error) return;
        this._error = value;
        this.refreshHint();
    }

    get error() {
        return this._error;
    }

    get shownError() {
        return this.error || this.inputError || null;
    }

    get autocomplete() {
        return this._autocomplete;
    }

    set autocomplete(value) {
        this._autocomplete = value;

        if (value === 'off')
            this.input.setAttribute('autocomplete', 'off');
    }

    refreshHint() {
        let error = this.shownError;
        let hint = error || this.hint;

        let hintEl = this.element.querySelector('.hint');
        hintEl.innerText = hint || '';
        hintEl.classList.toggle('filled', Boolean(hint));

        this.classList.toggle('invalid', Boolean(error));
    }

    refreshFix(selector, text) {
        let fix = this.element.querySelector(selector);
        display(fix, text);
        fix.innerText = text || '';
    }

    onFocus(hasFocus) {
        this.classList.toggle('focused', hasFocus);
    }

    onClear(event) {
        if (event.defaultPrevented) return;
        event.preventDefault();
        this.field = null;
        this.element.dispatchEvent(new Event('change'));
    }

    buildInput(type) {
        let template = `<input type="${type}" ng-model="$ctrl.field"></input>`;
        this.input = this.$compile(template)(this.$)[0];
    }

    /**
     * If input value is invalid, sets the error message as hint.
     */
    validateValue() {
        let error = this.input.checkValidity()
            ? null
            : this.input.validationMessage;

        if (error === this.inputError) return;
        this.inputError = error;
        this.refreshHint();
    }

    onChange($event) {
        // Changes doesn't reflect until appling async
        this.$.$applyAsync(() => {
            this.emit('change', {
                value: this.field,
                $event: $event
            });
        });
    }
}
Field.$inject = ['$element', '$scope', '$transclude'];

ngModule.vnComponent('vnField', {
    template: require('./index.html'),
    transclude: {
        prepend: '?prepend',
        append: '?append'
    },
    controller: Field,
    bindings: {
        type: '@?',
        autocomplete: '@?',
        placeholder: '@?',
        clearDisabled: '<?',
        value: '=?',
        info: '@?',
        required: '<?',
        prefix: '@?',
        suffix: '@?',
        hint: '@?',
        error: '<?',
        rule: '@?'
    }
});

function display(element, display) {
    element.style.display = display ? 'initial' : 'none';
}