text: import { sortBy, cloneDeep } from 'lodash';
  import { getIdFromGraphQLId } from '~/graphql_shared/utils';
  import { ListType, NOT_FILTER, AssigneeIdParamValues } from './constants';
  
  export function getMilestone() {
    return null;
  }
  
  export function updateListPosition(listObj) {
    const { listType } = listObj;
    let { position } = listObj;
    if (listType === ListType.closed) {
      position = Infinity;
    } else if (listType === ListType.backlog) {
      position = -Infinity;
    }
  
    return { ...listObj, position };
  }
  
  export function formatBoardLists(lists) {
    return lists.nodes.reduce((map, list) => {
      return {
        ...map,
        [list.id]: updateListPosition(list),
      };
    }, {});
  }
  
  export function formatIssue(issue) {
    return {
      ...issue,
      labels: issue.labels?.nodes || [],
      assignees: issue.assignees?.nodes || [],
    };
  }
  
  export function formatListIssues(listIssues) {
    const boardItems = {};
    let listItemsCount;
  
    const listData = listIssues.nodes.reduce((map, list) => {
      listItemsCount = list.issues.count;
      let sortedIssues = list.issues.edges.map((issueNode) => ({
        ...issueNode.node,
      }));
      sortedIssues = sortBy(sortedIssues, 'relativePosition');
  
      return {
        ...map,
        [list.id]: sortedIssues.map((i) => {
          const id = getIdFromGraphQLId(i.id);
  
          const listIssue = {
            ...i,
            id,
            labels: i.labels?.nodes || [],
            assignees: i.assignees?.nodes || [],
          };
  
          boardItems[id] = listIssue;
  
          return id;
        }),
      };
    }, {});
  
    return { listData, boardItems, listItemsCount };
  }
  
  export function formatListsPageInfo(lists) {
    const listData = lists.nodes.reduce((map, list) => {
      return {
        ...map,
        [list.id]: list.issues.pageInfo,
      };
    }, {});
    return listData;
  }
  
  export function fullBoardId(boardId) {
    return `gid://gitlab/Board/${boardId}`;
  }
  
  export function fullIterationId(id) {
    return `gid://gitlab/Iteration/${id}`;
  }
  
  export function fullUserId(id) {
    return `gid://gitlab/User/${id}`;
  }
  
  export function fullMilestoneId(id) {
    return `gid://gitlab/Milestone/${id}`;
  }
  
  export function fullLabelId(label) {
    if (label.project_id && label.project_id !== null) {
      return `gid://gitlab/ProjectLabel/${label.id}`;
    }
    return `gid://gitlab/GroupLabel/${label.id}`;
  }
  
  export function formatIssueInput(issueInput, boardConfig) {
    const { labelIds = [], assigneeIds = [] } = issueInput;
    const { labels, assigneeId, milestoneId } = boardConfig;
  
    return {
      milestoneId: milestoneId ? fullMilestoneId(milestoneId) : null,
      ...issueInput,
      labelIds: [...labelIds, ...(labels?.map((l) => fullLabelId(l)) || [])],
      assigneeIds: [...assigneeIds, ...(assigneeId ? [fullUserId(assigneeId)] : [])],
    };
  }
  
  export function shouldCloneCard(fromListType, toListType) {
    const involvesClosed = fromListType === ListType.closed || toListType === ListType.closed;
    const involvesBacklog = fromListType === ListType.backlog || toListType === ListType.backlog;
  
    if (involvesClosed || involvesBacklog) {
      return false;
    }
  
    if (fromListType !== toListType) {
      return true;
    }
  
    return false;
  }
  
  export function getMoveData(state, params) {
    const { boardItems, boardItemsByListId, boardLists } = state;
    const { itemId, fromListId, toListId } = params;
    const fromListType = boardLists[fromListId].listType;
    const toListType = boardLists[toListId].listType;
  
    return {
      reordering: fromListId === toListId,
      shouldClone: shouldCloneCard(fromListType, toListType),
      itemNotInToList: !boardItemsByListId[toListId].includes(itemId),
      originalIssue: cloneDeep(boardItems[itemId]),
      originalIndex: boardItemsByListId[fromListId].indexOf(itemId),
      ...params,
    };
  }
  
  export function moveItemListHelper(item, fromList, toList) {
    const updatedItem = item;
    if (
      toList.listType === ListType.label &&
      !updatedItem.labels.find((label) => label.id === toList.label.id)
    ) {
      updatedItem.labels.push(toList.label);
    }
    if (fromList?.label && fromList.listType === ListType.label) {
      updatedItem.labels = updatedItem.labels.filter((label) => fromList.label.id !== label.id);
    }
  
    if (
      toList.listType === ListType.assignee &&
      !updatedItem.assignees.find((assignee) => assignee.id === toList.assignee.id)
    ) {
      updatedItem.assignees.push(toList.assignee);
    }
    if (fromList?.assignee && fromList.listType === ListType.assignee) {
      updatedItem.assignees = updatedItem.assignees.filter(
        (assignee) => assignee.id !== fromList.assignee.id,
      );
    }
  
    return updatedItem;
  }
  
  export function isListDraggable(list) {
    return list.listType !== ListType.backlog && list.listType !== ListType.closed;
  }
  
  export function transformNotFilters(filters) {
    return Object.keys(filters)
      .filter((key) => key.startsWith(NOT_FILTER))
      .reduce((obj, key) => {
        return {
          ...obj,
          [key.substring(4, key.length - 1)]: filters[key],
        };
      }, {});
  }
  
  export function getSupportedParams(filters, supportedFilters) {
    return supportedFilters.reduce((acc, f) => {
      /**
       * TODO the API endpoint for the classic boards
       * accepts assignee wildcard value as 'assigneeId' param -
       * while the GraphQL query accepts the value in 'assigneWildcardId' field.
       * Once we deprecate the classics boards,
       * we should change the filtered search bar to use 'asssigneeWildcardId' as a token name.
       */
      if (f === 'assigneeId' && filters[f]) {
        return AssigneeIdParamValues.includes(filters[f])
          ? {
              ...acc,
              assigneeWildcardId: filters[f].toUpperCase(),
            }
          : acc;
      }
  
      if (filters[f]) {
        return {
          ...acc,
          [f]: filters[f],
        };
      }
  
      return acc;
    }, {});
  }
  
  // EE-specific feature. Find the implementation in the `ee/`-folder
  export function transformBoardConfig() {
    return '';
  }
  
  export default {
    getMilestone,
    formatIssue,
    formatListIssues,
    fullBoardId,
    fullLabelId,
    fullIterationId,
    isListDraggable,
    transformNotFilters,
  };
  