(function ($) {

  $('.selectx').each(function () {
    const $root = $(this);
    const $input = $root.find('.selectx-input');
    const $list = $root.find('.selectx-list');
    const $items = $root.find('.selectx-items');
    const $hidden = $root.find('.selectx-value');
    const action = $root.data('action');
    const minLength = +$root.data('min-length') || 2;
    const emptyText = $root.data('empty-text') || (window.anbarak && anbarak.i18n ? anbarak.i18n.nothing_found : 'Nothing found');
    const readonlyOnSelect = $root.data('readonly-on-select') === 1 || $root.data('readonly-on-select') === '1';
    const isSingle = $root.hasClass('selectx--single');

    // immutable origin
    const defaults = [...($root.data('defaults') || [])];

    // mutable state
    let selected = [...defaults];
    let cache = [];
    let xhr;

    renderSelected();

    // public API (registered AFTER state exists)
    $root.data('selectx', {
      update() {
        selected = [...defaults];
        renderSelected();
        renderList(cache);
      },

      get() {
        return [...selected];
      },

      setDefaults(items) {
        defaults.length = 0;
        defaults.push(...items);
        selected = [...defaults];
        renderSelected();
      },

      set(items) {
        selected = [...items];
        renderSelected();
      },

      clear() {
        selected = [];
        renderSelected();
      }
    });

    function getItemLabel(item) {
      if (item.label) return item.label;

      const labels = item.types ? item.types.map(type => type.label).join(', ') : '';
      return labels ? item.name + ' (' + labels + ')' : item.name;
    }

    function getItemValue(item) {
      return item.value || item.phone || item.name || item.id;
    }

    function renderSelected() {
      $items.find('.tag').remove();

      selected.forEach(item => {
        $('<span class="tag">')
          .addClass('bg-gray-100 border border-gray-300 cursor-default text-sm px-2 py-1 rounded-full flex items-center dark:bg-neutral-800 dark:border-[#444] dark:text-gray-200')
          .text(getItemLabel(item))
          .prepend(
            $('<button type="button">×</button>')
              .addClass('text-2xl cursor-pointer px-1 text-red-800')
              .on('click', () => removeItem(item.id))
          )
          .appendTo($items);
      });

      if (isSingle) {
        const selectedItem = selected[0];
        $input.val(selectedItem ? getItemValue(selectedItem) : '');
        $input.prop('readonly', readonlyOnSelect && !!selectedItem);
      }

      $hidden.val(selected.map(i => i.id).join(','));
    }

    function removeItem(id) {
      selected = selected.filter(i => i.id !== id);
      renderSelected();
      $root.trigger('selectx:clear');
    }

    function renderList(items) {
      $list.empty();

      if (!items.length) {
        $('<li>')
          .addClass('px-3 py-2 text-gray-400')
          .text(emptyText)
          .appendTo($list);
      }

      items.forEach(item => {
        const isSelected = selected.some(s => s.id === item.id);

        $('<li>')
          .addClass('px-3 py-2 cursor-pointer rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800')
          .toggleClass('bg-orange-50 text-orange-700 dark:bg-orange-950 dark:text-orange-300', isSelected)
          .text(getItemLabel(item))
          .on('click', () => {
            if (isSingle) {
              selected = [item];
            } else if (!isSelected) {
              selected.push(item);
            }

            renderSelected();
            $list.hide();
            if (!isSingle) $input.val('');
            $root.trigger('selectx:select', [item]);
          })
          .appendTo($list);
      });

      $list.show();
    }

    $input.on('focus', () => {
      if (cache.length) renderList(cache);
    });

    $input.on('input', function () {
      const q = this.value.trim();
      if (q.length < minLength) return renderList(cache);

      if (xhr) xhr.abort();

      xhr = $.get(ajaxurl, {
        action,
        q,
        security: anbarak.nonce
      }).done(res => {
        cache = res.data || [];
        renderList(cache);
      });
    });

    $(document).on('click', e => {
      if (!$root.is(e.target) && !$root.has(e.target).length) {
        $list.hide();
      }
    });
  });

})(jQuery);
