/**
 * Quantity stepper for number inputs (vanilla front-end copy).
 *
 * Injects `<div class="numberButtons">` with `+` and `−` controls beside
 * the target input, enforces optional `data-min` / `data-max` bounds, and
 * toggles `.disabled` on the buttons when the value hits the limits.
 *
 * Replaces the previous mtcNumberArrows plugin on `$.fn`. Consumers can
 * either construct directly:
 *
 *   import NumberArrows from '@core/js/plugins/mtc_number_arrows.js';
 *   const instance = new NumberArrows(inputEl);
 *
 * or use the `v-number-arrows` Vue directive, which calls this for them.
 */

const DEFAULTS = {
    up_arrow: '<i class="fa fa-caret-up"></i>',
    down_arrow: '<i class="fa fa-caret-down"></i>',
};

export default class NumberArrows {

    constructor(element, options = {}) {
        if (!element) {
            return;
        }
        this.element = element;
        this.settings = { ...DEFAULTS, ...options };
        this.init();
    }

    init() {
        this.addMarkup();
        this.bind();
    }

    getMinMax(which) {
        const ds = this.element.dataset || {};
        if (which === 'min') {
            const raw = ds.min;
            return (raw !== undefined && raw !== '') ? parseInt(raw, 10) : 0;
        }
        if (which === 'max') {
            const raw = ds.max;
            return (raw !== undefined && raw !== '') ? parseInt(raw, 10) : Number.MAX_VALUE;
        }
        return 0;
    }

    addMarkup() {
        const number = this.element;
        const wrapper = number.closest('.inputWrap');

        const buttons = document.createElement('div');
        buttons.className = 'numberButtons';
        buttons.innerHTML =
            `<div class="numberButton add">${this.settings.up_arrow}</div>` +
            `<div class="numberButton subtract">${this.settings.down_arrow}</div>`;

        number.insertAdjacentElement('afterend', buttons);

        if (wrapper) {
            wrapper.classList.add('numberArrowWrap');
        }

        this.buttons = buttons;
        this.addButton = buttons.querySelector('.add');
        this.subtractButton = buttons.querySelector('.subtract');

        this.checkClass();
    }

    bind() {
        const number = this.element;

        this._onSubtract = () => {
            const count = parseInt(number.value, 10) || 0;
            if (count > this.getMinMax('min')) {
                number.focus();
                number.value = count - 1;
                number.dispatchEvent(new Event('change', { bubbles: true }));
            }
        };

        this._onAdd = () => {
            const count = parseInt(number.value, 10) || 0;
            if (count < this.getMinMax('max')) {
                number.focus();
                number.value = count + 1;
                number.dispatchEvent(new Event('change', { bubbles: true }));
            }
        };

        this._onChange = () => this.checkClass();

        this._onFocusOut = () => {
            const value = parseInt(number.value, 10);
            if (Number.isNaN(value)) {
                return;
            }
            const min = this.getMinMax('min');
            const max = this.getMinMax('max');
            if (value < min) {
                number.value = min;
                number.dispatchEvent(new Event('change', { bubbles: true }));
            } else if (value > max) {
                number.value = max;
                number.dispatchEvent(new Event('change', { bubbles: true }));
            }
        };

        this.subtractButton?.addEventListener('click', this._onSubtract);
        this.addButton?.addEventListener('click', this._onAdd);
        number.addEventListener('change', this._onChange);
        number.addEventListener('focusout', this._onFocusOut);
    }

    checkClass() {
        const count = parseInt(this.element.value, 10) || 0;
        const min = this.getMinMax('min');
        const max = this.getMinMax('max');

        this.subtractButton?.classList.toggle('disabled', count <= min);
        this.addButton?.classList.toggle('disabled', count >= max);
    }

    destroy() {
        const number = this.element;
        this.subtractButton?.removeEventListener('click', this._onSubtract);
        this.addButton?.removeEventListener('click', this._onAdd);
        number.removeEventListener('change', this._onChange);
        number.removeEventListener('focusout', this._onFocusOut);

        this.buttons?.remove();
        number.closest('.inputWrap')?.classList.remove('numberArrowWrap');
    }
}
