/**  
 * @since Last modified: 2024-07-11 09:30:49
 * @class NumberElem
 * @description The custom element : ax-number .
 * @see {@link https://codepen.io/axui/pen/YzMVvWP|demo @ codepen}
 * @example
 * <ax-number name="demo" value="book" label="Reading"></ax-number>;
 */
import { T_el, T_obj } from '../../../types/ax';
import ax from '../ax';
import prefix from '../global/prefix';
import createEl from '../utils/createEl';
import createTools from '../utils/createTools';
import elState from '../utils/elState';
import getAttrArr from '../utils/getAttrArr';
import getAttrBool from '../utils/getAttrBool';
import isEmpty from '../utils/isEmpty';
import isNull from '../utils/isNull';
import renderTpl from '../utils/renderTpl';
import PlainElem from './PlainElem';
class NumberElem extends PlainElem {
    labelEl: any;
    inputEl: any;
    toolsEl: any;
    propsRaw: any;
    inputEvent: any;
    tipsEl: any;
    incrEl: any;
    decrEl: any;
    constructor() {
        super();
        super.createObs();
        this.getRawData();
        this.fillWrap(this.propsProxy);
        this.inputEvent = new Event('input');
        this.reset = () => {
            for (let k in this.propsRaw) {
                (this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
            }
            this.inputEl.value = '';
            this.inputEl.dispatchEvent(this.inputEvent);
            this.listen({ name: 'reset' });
        }
        this.clear = () => {
            this.inputEl.value = '';
            this.inputEl.dispatchEvent(this.inputEvent);
            this.listen({ name: 'clear' });
        }
        this.observer.ins.on('set', (data: T_obj) => {
            this.initialized && this.updateCache({ [data.key]: data.value });
        });
        this.on('input', (value: string) => {
            let step = this.propsProxy.step || 1;
            if (this.propsProxy.max) {
                if (~~value + step > ~~this.propsProxy.max) {
                    this.incrEl.setAttribute('disabled', '');
                } else {
                    this.incrEl.removeAttribute('disabled');
                }
            }
            if (this.propsProxy.min) {
                if (~~value - step < ~~this.propsProxy.min) {
                    this.decrEl.setAttribute('disabled', '');
                } else {
                    this.decrEl.setAttribute('disabled');
                }
            }
        });
    }
    static lazyAttrs = ['stor-name'];
    static custAttrs = [
        'class',
        'name', 'placeholder', 'layout', 'size', 'max', 'min', 'step',
        'on-init', 'on-reset', 'on-clear', 'on-change', 'on-input', 'on-set', 'on-exceed',
    ];
    static boolAttrs = ['tips', 'disabled', 'readonly'];
    static get observedAttributes() {
        return ['value', ...this.custAttrs, ...this.boolAttrs];
    }
    attributeChangedCallback(name: string, oldVal: string, newVal: string) {
        this.propsProxy[name] = NumberElem.boolAttrs.includes(name) ? getAttrBool(newVal) : newVal;
        if (NumberElem.boolAttrs.includes(name)) {
            this.inputEl[name === 'readonly' ? 'readOnly' : name] = this.propsProxy[name];
            if (name === 'tips') {
                if(this.propsProxy.tips){
                    elState(this.tipsEl).isVirtual && this.appendChild(this.tipsEl);
                }else{
                    this.tipsEl.remove();   
                }
            }
        } else if (['value', 'max', 'min', 'step'].includes(name)) {
            this.inputEl[name] = newVal;
            (name === 'max' || name === 'min') && this.updateTips();
        }  else if (['name', 'placeholder'].includes(name)) {
            this.inputEl.setAttribute(name, newVal);
        }
        if (oldVal !== newVal) {
            this.listen({ name: 'change', params: [{ name, oldVal, newVal }] });
        }
    }
    connectedCallback() {
        this.render();
        this.initialized = true;
        this.listen({ name: 'init' });
    }
    disconnectedCallback() {
    }
    adoptedCallback() {
    }
    getRawData() {
        [...NumberElem.custAttrs, ...NumberElem.lazyAttrs].forEach((k: string) => {
            this.propsRaw[k] = this.getAttribute(k);
        });
        NumberElem.boolAttrs.forEach((k: string) => {
            this.propsRaw[k] = getAttrBool(this.getAttribute(k));
        });
        this.propsRaw.value = this.getAttribute('value') || this.innerHTML;
        for (let k in this.propsRaw) {
            this.propsProxy[k] = this.propsRaw[k]
        }
        this.innerHTML = '';
    }
    fillWrap(data: T_obj) {
        this.wrapEl = createEl('div', { role: 'wrap' });
        this.inputEl = createEl('input', { type: 'number', name: data.name, placeholder: data.placeholder || ax.lang.form.placeholder });
        data.value && (this.inputEl.value = data.value);
        this.decrEl = createEl('i', { role: 'decrease' }, 'minus');
        this.incrEl = createEl('i', { role: 'increase' }, 'plus');
        this.wrapEl.append(this.decrEl, this.inputEl, this.incrEl);
        this.tipsEl = createEl('div', { role: 'tips' });
    }
    updateTips() {console.log(0)
        let max = isNull(this.propsProxy.max) ? '+∞' : this.propsProxy.max,
            min = isNull(this.propsProxy.min) ? '-∞' : this.propsProxy.min,
            val = this.propsProxy.value,
            old = ~~val,
            str = '';
        if (max === '+∞' && min === '-∞') { return this }
        if (max !== '+∞' && min !== '-∞') {
            str = renderTpl(ax.lang.form.limitNumber, { max, min });
            if (~~val >= ~~min && ~~val <= ~~max) {
                this.removeAttribute('exceeded');
                this.decrEl.removeAttribute('disabled');
                this.incrEl.removeAttribute('disabled');
            } else {
                this.setAttribute('exceeded', '');
                str += ax.lang.form.exceed;
                val = (~~val < ~~min) ? min : (~~val > ~~max) ? max : val;
                ~~val > old ? this.decrEl.setAttribute('disabled', '') : this.incrEl.setAttribute('disabled', '');
                this.listen({ name: 'exceed', params: [val, old] });
            }
        } else if (max !== '+∞') {console.log(1)
            str = renderTpl(ax.lang.form.maxNumber, { max });
            if (~~val > ~~max) {
                val = max;
                this.setAttribute('exceeded', '');
                str += ax.lang.form.exceed;
                this.incrEl.setAttribute('disabled', '');
                this.listen({ name: 'exceed', params: [val, old] });
            } else {
                this.removeAttribute('exceeded');
                this.incrEl.removeAttribute('disabled');
            }console.log(2)
        } else if (min !== '-∞') {
            str = renderTpl(ax.lang.form.minNumber, { min });
            if (~~val < ~~min) {
                val = min;
                this.setAttribute('exceeded', '');
                str += ax.lang.form.exceed;
                this.decrEl.setAttribute('disabled', '');
                this.listen({ name: 'exceed', params: [val, old] });
            } else {
                this.removeAttribute('exceeded');
                this.decrEl.removeAttribute('disabled');
            }
        }
        if (val !== this.propsProxy.value) {
            this.setAttribute('value', val);
        }console.log(str)
        this.tipsEl.innerHTML = str;
    }
    render() {
        this.appendChild(this.wrapEl);
        (this.propsProxy.tips && (this.propsProxy.max || this.propsProxy.min) && elState(this.tipsEl).isVirtual) ? this.appendChild(this.tipsEl) : null;
        this.decrEl.onclick = () => {
            this.inputEl.stepDown();
            this.inputEl.dispatchEvent(new Event('input'));
        }
        this.incrEl.onclick = () => {
            this.inputEl.stepUp();
            this.inputEl.dispatchEvent(new Event('input'));
        }
        this.inputEl.addEventListener('input', (e: any) => {
            this.propsProxy.value = this.inputEl.value;
            this.updateTips();
            this.listen({ name: 'input', params: [this.inputEl.value] });
        }, false);
    }
}
window.customElements.define("ax-number", NumberElem);
export default NumberElem;
