import { attributeSelector } from './selector-utilities';
import { stripMultilineIndention } from './string-utilities';
import { extractPrefixedAttributesFromElement } from '@nimius/dom-utility';

const ATTRIBUTE = Object.freeze({
    BASE: 'data-item-filter',
    ITEM_VALUE: 'data-item-filter-value',
    RESET_TRIGGER: 'data-item-filter-reset',
});

/**
 * Makes a list filterable via input element.
 *
 * @example
 *  <input
 *      type="text"
 *      data-item-filter
 *      data-item-filter-target="#items-container-123" />
 *
 *  <ul id="items-container-123">
 *      <li data-item-filter-value="foo"><input type="checkbox">Foo</li>
 *      <li data-item-filter-value="bar"><input type="checkbox">Bar</li>
 *      <li data-item-filter-value="baz"><input type="checkbox">Baz</li>
 *  </ul>
 *
 *  <!-- optional -->
 *  <button data-item-filter-reset>
 *      Reset filter lists
 *  </button>
 */
export class ItemFilter {

    /**
     * @param {HTMLElement} node
     */
    constructor(node) {
        /** @private {HTMLElement} */
        this.input = node;

        this.options = extractPrefixedAttributesFromElement(node, `${ATTRIBUTE.BASE}-`);

        if (this.options.target) {
            this.target = document.querySelector(this.options.target);

            if (this.target && this.input instanceof HTMLInputElement) {
                this.bindQueryObserver();
                this.bindResetTriggers();
            }
        }

        this.printHelpfulWarningMessages();
    }

    /**
     * Applies the given search query to the children.
     *
     * @param {string} query
     * @public
     */
    updateItems(query) {
        const searchString = query.toLowerCase();

        for (const element of this.target.querySelectorAll(attributeSelector(ATTRIBUTE.ITEM_VALUE))) {
            const value = element.getAttribute(ATTRIBUTE.ITEM_VALUE);
            const matches = value.toLowerCase().indexOf(searchString) !== -1 || query === '';
            element.style.display = matches ? '' : 'none';
        }
    }

    /**
     * Bind input change listener
     *
     * @private
     */
    bindQueryObserver() {
        this.input.addEventListener('input', event => this.updateItems(event.target.value));
    }

    /**
     * Bind optional reset triggers
     *
     * @private
     */
    bindResetTriggers() {
        for (const trigger of document.querySelectorAll(attributeSelector(ATTRIBUTE.RESET_TRIGGER))) {
            trigger.addEventListener('click', () => this.reset());
        }
    }

    /**
     * Reset filter query
     *
     * @public
     */
    reset() {
        this.input.value = '';
        this.updateItems('');
    }

    /** @private */
    printHelpfulWarningMessages() {
        if (!(this.input instanceof HTMLInputElement)) {
            console.warn(stripMultilineIndention(`
                Please apply '${ATTRIBUTE.BASE}' to an element of type "HTMLInputElement".
            `), { itemFilter: this });
        }
        if (!this.options.target || !this.target) {
            console.warn(stripMultilineIndention(`
                No target item list found. Please set 'data-item-list-target' on the input node.
            `), { itemFilter: this });
            return;
        }
        if (this.target.querySelectorAll(attributeSelector(ATTRIBUTE.ITEM_VALUE)).length === 0) {
            console.warn(stripMultilineIndention(`
                No filterable items found. Please add items with ${ATTRIBUTE.ITEM_VALUE} within
                the target list.
            `), { itemFilter: this });
        }
    }

}
