(function (root, factory) {
  const filterCommands = factory();
  if (typeof module === 'object' && module.exports) module.exports = filterCommands;
  if (root) root.filterCommands = filterCommands;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
  function filterCommands(commands, filter) {
    const term = String(filter || '').toLowerCase();
    return commands.filter(command => command.name.toLowerCase().includes(term));
  }

  filterCommands.nextSelection = function nextSelection(current, key, count) {
    if (count < 1) return -1;
    if (key === 'ArrowDown') return (current + 1 + count) % count;
    if (key === 'ArrowUp') return (current - 1 + count) % count;
    return current;
  };

  filterCommands.searchUrl = function searchUrl(query, page, scope, continuation) {
    const streamPages = continuation ?
      (continuation.issues ? '&issues_page=' + encodeURIComponent(continuation.issues) : '') +
      (continuation.pulls ? '&pulls_page=' + encodeURIComponent(continuation.pulls) : '') : '';
    return 'api/v1/search?q=' + encodeURIComponent(query) + '&limit=10&page=' + page +
      '&kind=' + encodeURIComponent(scope.kind) + '&state=' + encodeURIComponent(scope.state) +
      (scope.repository ? '&repository=' + encodeURIComponent(scope.repository) : '') + streamPages;
  };

  filterCommands.createGlobalSearchController = function createGlobalSearchController(options) {
    const search = options.search;
    const onState = options.onState;
    const delay = options.delay === undefined ? 250 : options.delay;
    let timer = null;
    let generation = 0;
    let activeController = null;
    let scope = { kind:'all', state:'all' };
    let state = { status: 'idle', query: '', items: [], more: false, next: 1, scope };

    function publish(next) {
      state = next;
      onState(next);
      return state;
    }

    async function requestPage(query, page, current, append, continuation) {
      const requestController = new AbortController();
      activeController = requestController;
      try {
        const requestScope = { ...scope };
        const result = await search(
          query, requestController.signal, page, requestScope, continuation
        );
        const partial = result.partial === true;
        const incoming = result.items || result;
        const combined = append ? state.items.concat(incoming) : incoming;
        const items = [...new Map((combined || []).map(item =>
          [`${item.kind}:${item.repository}:${item.number}`, item]
        )).values()];
        if (current === generation) return publish({
          status: 'ready', query, items, partial,
          more: !!result.has_more,
          next: result.next_page,
          continuation:result.continuation,
          failedStreams:result.failed_streams || [],
          scope:requestScope,
        });
      } catch (error) {
        if (error && error.name === 'AbortError') return;
        if (current === generation) return publish(append
          ? { ...state, status: 'ready' }
          : { status: 'error', query, items: [], error, scope:{ ...scope } });
      } finally {
        if (activeController === requestController) activeController = null;
      }
    }

    return {
      setQuery(value) {
        const query = String(value || '').trim();
        generation += 1;
        const current = generation;
        if (timer !== null) clearTimeout(timer);
        if (activeController !== null) activeController.abort();
        activeController = null;
        if (query.length < 2) {
          publish({ status: 'idle', query, items: [], more: false, next: 1, scope:{ ...scope } });
          return;
        }
        publish({ status: 'loading', query, items: [], more: false, next: 1, scope:{ ...scope } });
        timer = setTimeout(() => requestPage(query, 1, current, false), delay);
      },
      setScope(value) {
        const repository = typeof value?.repository === 'string' &&
          /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(value.repository.trim())
          ? value.repository.trim() : '';
        const next = {
          kind:['all', 'issue', 'pull'].includes(value?.kind) ? value.kind : 'all',
          state:['all', 'open', 'closed'].includes(value?.state) ? value.state : 'all',
          ...(repository ? { repository } : {}),
        };
        if (next.kind === scope.kind && next.state === scope.state &&
            (next.repository || '') === (scope.repository || '')) return;
        const query = state.query;
        scope = next;
        this.setQuery(query);
      },
      loadMore() {
        if (state.status !== 'ready' || !state.more || activeController) return Promise.resolve(state);
        const current = generation;
        const page = state.next;
        return requestPage(state.query, page, current, true, state.continuation);
      },
    };
  };

  return filterCommands;
});
