import { CANCELLED_STATUS } from "discourse/lib/autocomplete";
import { debounce } from "@ember/runloop";
import getUrl from "discourse-common/lib/get-url";
import { Promise } from "rsvp";

let cache = {},
  cacheTopicId,
  cacheTime,
  currentTerm,
  oldSearch;

function performSearch(
  term,
  topicId,
  includeGroups,
  includeMentionableGroups,
  includeMessageableGroups,
  allowedUsers,
  group,
  resultsFn
) {
  let cached = cache[term];
  if (cached) {
    resultsFn(cached);
    return;
  }

  // need to be able to cancel this
  oldSearch = $.ajax(getUrl("/u/search/users"), {
    data: {
      term,
      topic_id: topicId,
      include_groups: includeGroups,
      include_mentionable_groups: includeMentionableGroups,
      include_messageable_groups: includeMessageableGroups,
      group,
      topic_allowed_users: allowedUsers,
    },
  });

  let returnVal = CANCELLED_STATUS;

  oldSearch
    .then(function (r) {
      cache[term] = r;
      cacheTime = new Date();
      // If there is a newer search term, return null
      if (term === currentTerm) {
        returnVal = r;
      }
    })
    .always(function () {
      oldSearch = null;
      resultsFn(returnVal);
    });
}

function organizeResults(r, options) {
  if (r === CANCELLED_STATUS) {
    return r;
  }

  let exclude = options.exclude || [],
    limit = options.limit || 5,
    users = [],
    emails = [],
    groups = [],
    results = [];

  if (r.users) {
    r.users.every(function (u) {
      if (exclude.indexOf(u.username) === -1) {
        users.push(u);
        results.push(u);
      }
      return results.length <= limit;
    });
  }

  if (options.term.match(/@/)) {
    let e = { username: options.term };
    emails = [e];
    results.push(e);
  }

  if (r.groups) {
    r.groups.every(function (g) {
      if (
        results.length > limit &&
        options.term.toLowerCase() !== g.name.toLowerCase()
      ) {
        return false;
      }
      if (exclude.indexOf(g.name) === -1) {
        groups.push(g);
        results.push(g);
      }
      return true;
    });
  }

  results.users = users;
  results.emails = emails;
  results.groups = groups;
  return results;
}

export default function userSearch(options) {
  let term = options.term || "",
    includeGroups = options.includeGroups,
    includeMentionableGroups = options.includeMentionableGroups,
    includeMessageableGroups = options.includeMessageableGroups,
    allowedUsers = options.allowedUsers,
    topicId = options.topicId,
    group = options.group;

  if (oldSearch) {
    oldSearch.abort();
    oldSearch = null;
  }

  currentTerm = term;

  return new Promise(function (resolve) {
    // TODO site setting for allowed regex in username
    if (term.match(/[^\w_\-\.@\+]/)) {
      resolve([]);
      return;
    }
    if (new Date() - cacheTime > 30000 || cacheTopicId !== topicId) {
      cache = {};
    }

    cacheTopicId = topicId;

    let clearPromise = setTimeout(function () {
      resolve(CANCELLED_STATUS);
    }, 5000);

    // TODO: Use discouseDebounce after it is available on stable.
    debounce(
      this,
      function () {
        performSearch(
          term,
          topicId,
          includeGroups,
          includeMentionableGroups,
          includeMessageableGroups,
          allowedUsers,
          group,
          function (r) {
            clearTimeout(clearPromise);
            resolve(organizeResults(r, options));
          }
        );
      },
      300
    );
  });
}
