/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: BUSL-1.1
 */

import { get, set } from '@ember/object';
import MultiMap from 'mnemonist/multi-map';

/**
 * Checks are ember-data-model-fragments, so we can't just
 * concat it, we have to loop through all the items in order to merge
 * We also need to avoid repeating Node checks here as the service and the
 * proxy is likely to be on the same node, without adding something extra here
 * the node check will likely end up in the list twice.
 *
 * @param {Array} checks - Multiple lists of healthchecks to merge each one of the items in this array should be a further array of healthchecks
 * @param {Boolean} exposed - Whether the checks should be marked as exposed via the proxy or not
 * @param {Object} MMap - A MultiMap class. This is only exposed to allow for an easier interface but still allow an injectable MultiMap if we choose to do that during testing
 * @returns {Array} - The final array of all of the healthchecks with any duplicate node checks removed, and also marked as exposed if required
 */
export default (checks = [], exposed = false, MMap = MultiMap) => {
  const ids = new MMap();
  const a = checks.shift();
  const result = a
    .map((item) => {
      // its a Node check (ServiceName === ""), record this one so we
      // don't end up with duplicates of it
      if (item.ServiceName === '') {
        ids.set(item.Node, item.CheckID);
      }
      return item;
    })
    // go through all remaining lists of checks adding each check to the
    // list if its not a node check that has been already added
    .concat(
      checks.reduce((prev, items) => {
        if (typeof items === 'undefined') {
          return prev;
        }
        return prev.concat(
          items.reduce((prev, item) => {
            if (item.ServiceName === '') {
              if ((ids.get(item.Node) || []).includes(item.CheckID)) {
                return prev;
              }
              // if the node check hasn't been added yet, record this one
              // so we don't end up with duplicates of it
              ids.set(item.Node, item.CheckID);
            }
            prev.push(item);
            return prev;
          }, [])
        );
      }, [])
    );
  // if checks are exposed via the proxy, find the ones that are exposable
  // (ones of a certain type) and set them as exposed
  // TODO: consider moving this out of here so we aren't doing too much in one util
  if (exposed) {
    result
      .filter((item) => get(item, 'Exposable'))
      .forEach((item) => {
        set(item, 'Exposed', exposed);
      });
  }
  return result;
};
