import countButton from '../../../elements/count-button.hbs';

// ===== HELPERS =====

function normalizeOptions(options) {
    return {
        inputSel: '#quantity-field',

        min: 1,

        enhancedInputClass: 'count-stepper__input',
        enhancedParentClass: 'count-stepper',

        onChange: null,

        ...options,
    };
}

function toInt(value) {
    const n = parseInt(`${value || ''}`.trim(), 10);

    return Number.isFinite(n) ? n : NaN;
}

function clampMin(n, min) {
    return Math.max(min, n);
}

function ensureQty(value, fallback) {
    const n = toInt(value);

    return Number.isFinite(n) ? n : fallback;
}

function buildBtn(type, disabled) {
    return countButton({
        type,
        icon: type === 'plus' ? 'fa-plus' : 'fa-minus',
        ariaLabel: type === 'plus' ? 'Increase quantity' : 'Decrease quantity',
        disabled: !!disabled,
    });
}

function getButtonsWrap($input) {
    return $input.parent();
}

function getMinusBtn($wrap) {
    return $wrap.find('[data-count-btn][data-count-type="minus"]').first();
}

function getPlusBtn($wrap) {
    return $wrap.find('[data-count-btn][data-count-type="plus"]').first();
}

function updateButtons($input, opt) {
    const $wrap = getButtonsWrap($input);
    const qty = ensureQty($input.val(), opt.min);

    const $minus = getMinusBtn($wrap);

    if ($minus.length) {
        $minus.prop('disabled', qty <= opt.min);
    }
}

function setQty($input, opt, qty) {
    const next = clampMin(qty, opt.min);

    $input.val(`${next}`);
    updateButtons($input, opt);

    if (typeof opt.onChange === 'function') {
        opt.onChange(next, $input.get(0));
    }
}

function ensureButtons($input, opt) {
    const $parent = getButtonsWrap($input);

    $input.addClass(opt.enhancedInputClass);
    $parent.addClass(opt.enhancedParentClass);

    const hasMinus = getMinusBtn($parent).length;
    const hasPlus = getPlusBtn($parent).length;

    if (!hasMinus) {
        $input.before(buildBtn('minus', true));
    }

    if (!hasPlus) {
        $input.after(buildBtn('plus', false));
    }

    const initial = ensureQty($input.val(), opt.min);

    setQty($input, opt, initial);
}

function getInputs($root, inputSel) {
    const $scope = $root && $root.length ? $root : $(document);
    const $self = $scope.is(inputSel) ? $scope : $();
    const $found = $scope.find(inputSel);

    return $self.add($found);
}

function getNamespace(inputSel) {
    return `.countStepper_${inputSel.replace(/[^a-zA-Z0-9_-]/g, '')}`;
}

// ===== FACTORY =====

export function createCountStepper(options = {}) {
    const OPT = normalizeOptions(options);

    if (!OPT.inputSel) {
        throw new Error('[createCountStepper] Missing inputSel');
    }

    const NS = getNamespace(OPT.inputSel);

    function init($root) {
        getInputs($root, OPT.inputSel).each(function () {
            ensureButtons($(this), OPT);
        });
    }

    $(document)
        .off(`click${NS}`, '[data-count-btn]')
        .on(`click${NS}`, '[data-count-btn]', function (e) {
            const $btn = $(this);
            const $parent = $btn.parent();
            const $input = $parent.find(OPT.inputSel).first();

            if (!$input.length) {
                return;
            }

            e.preventDefault();

            const type = ($btn.attr('data-count-type') || '').toLowerCase();
            const current = ensureQty($input.val(), OPT.min);

            if (type === 'plus') {
                setQty($input, OPT, current + 1);
            }

            if (type === 'minus') {
                setQty($input, OPT, current - 1);
            }
        });

    $(document)
        .off(`input${NS} change${NS}`, OPT.inputSel)
        .on(`input${NS} change${NS}`, OPT.inputSel, function () {
            updateButtons($(this), OPT);
        });

    return { init };
}
