text: /* eslint-disable no-shadow, no-param-reassign,consistent-return */
  /* global List */
  /* global ListIssue */
  import { sortBy, pick } from 'lodash';
  import Vue from 'vue';
  import Cookies from 'js-cookie';
  import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
  import {
    urlParamsToObject,
    getUrlParamsArray,
    parseBoolean,
    convertObjectPropsToCamelCase,
  } from '~/lib/utils/common_utils';
  import createDefaultClient from '~/lib/graphql';
  import axios from '~/lib/utils/axios_utils';
  import { mergeUrlParams } from '~/lib/utils/url_utility';
  import { getIdFromGraphQLId } from '~/graphql_shared/utils';
  import eventHub from '../eventhub';
  import { ListType } from '../constants';
  import IssueProject from '../models/project';
  import ListLabel from '../models/label';
  import ListAssignee from '../models/assignee';
  import ListMilestone from '../models/milestone';
  
  import createBoardMutation from '../queries/board.mutation.graphql';
  
  const PER_PAGE = 20;
  export const gqlClient = createDefaultClient();
  
  const boardsStore = {
    disabled: false,
    timeTracking: {
      limitToHours: false,
    },
    scopedLabels: {
      enabled: false,
    },
    filter: {
      path: '',
    },
    state: {
      currentBoard: {
        labels: [],
      },
      currentPage: '',
      endpoints: {},
    },
    detail: {
      issue: {},
      list: {},
    },
    moving: {
      issue: {},
      list: {},
    },
    multiSelect: { list: [] },
  
    setEndpoints({
      boardsEndpoint,
      listsEndpoint,
      bulkUpdatePath,
      boardId,
      recentBoardsEndpoint,
      fullPath,
    }) {
      const listsEndpointGenerate = `${listsEndpoint}/generate.json`;
      this.state.endpoints = {
        boardsEndpoint,
        boardId,
        listsEndpoint,
        listsEndpointGenerate,
        bulkUpdatePath,
        fullPath,
        recentBoardsEndpoint: `${recentBoardsEndpoint}.json`,
      };
    },
    create() {
      this.state.lists = [];
      this.filter.path = getUrlParamsArray().join('&');
      this.detail = {
        issue: {},
        list: {},
      };
    },
    showPage(page) {
      this.state.currentPage = page;
    },
    updateListPosition(listObj) {
      const listType = listObj.listType || listObj.list_type;
      let { position } = listObj;
      if (listType === ListType.closed) {
        position = Infinity;
      } else if (listType === ListType.backlog) {
        position = -1;
      }
  
      const list = new List({ ...listObj, position });
      return list;
    },
    addList(listObj) {
      const list = this.updateListPosition(listObj);
      this.state.lists = sortBy([...this.state.lists, list], 'position');
      return list;
    },
    new(listObj) {
      const list = this.addList(listObj);
      const backlogList = this.findList('type', 'backlog', 'backlog');
  
      list
        .save()
        .then(() => {
          // Remove any new issues from the backlog
          // as they will be visible in the new list
          list.issues.forEach(backlogList.removeIssue.bind(backlogList));
          this.state.lists = sortBy(this.state.lists, 'position');
        })
        .catch(() => {
          // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821
        });
    },
  
    updateNewListDropdown(listId) {
      // eslint-disable-next-line no-unused-expressions
      document
        .querySelector(`.js-board-list-${getIdFromGraphQLId(listId)}`)
        ?.classList.remove('is-active');
    },
    shouldAddBlankState() {
      // Decide whether to add the blank state
      return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0];
    },
    addBlankState() {
      if (!this.shouldAddBlankState() || this.welcomeIsHidden()) return;
  
      this.generateDefaultLists()
        .then(res => res.data)
        .then(data => Promise.all(data.map(list => this.addList(list))))
        .catch(() => {
          this.removeList(undefined, 'label');
        });
    },
  
    findIssueLabel(issue, findLabel) {
      return issue.labels.find(label => label.id === findLabel.id);
    },
  
    goToNextPage(list) {
      if (list.issuesSize > list.issues.length) {
        if (list.issues.length / PER_PAGE >= 1) {
          list.page += 1;
        }
  
        return list.getIssues(false);
      }
    },
  
    addListIssue(list, issue, listFrom, newIndex) {
      let moveBeforeId = null;
      let moveAfterId = null;
  
      if (!list.findIssue(issue.id)) {
        if (newIndex !== undefined) {
          list.issues.splice(newIndex, 0, issue);
  
          if (list.issues[newIndex - 1]) {
            moveBeforeId = list.issues[newIndex - 1].id;
          }
  
          if (list.issues[newIndex + 1]) {
            moveAfterId = list.issues[newIndex + 1].id;
          }
        } else {
          list.issues.push(issue);
        }
  
        if (list.label) {
          issue.addLabel(list.label);
        }
  
        if (list.assignee) {
          if (listFrom && listFrom.type === 'assignee') {
            issue.removeAssignee(listFrom.assignee);
          }
          issue.addAssignee(list.assignee);
        }
  
        if (IS_EE && list.milestone) {
          if (listFrom && listFrom.type === 'milestone') {
            issue.removeMilestone(listFrom.milestone);
          }
          issue.addMilestone(list.milestone);
        }
  
        if (listFrom) {
          list.issuesSize += 1;
  
          list.updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId);
        }
      }
    },
    findListIssue(list, id) {
      return list.issues.find(issue => issue.id === id);
    },
  
    welcomeIsHidden() {
      return parseBoolean(Cookies.get('issue_board_welcome_hidden'));
    },
    removeList(id, type = 'blank') {
      const list = this.findList('id', id, type);
  
      if (!list) return;
  
      this.state.lists = this.state.lists.filter(list => list.id !== id);
    },
    moveList(listFrom, orderLists) {
      orderLists.forEach((id, i) => {
        const list = this.findList('id', parseInt(id, 10));
  
        list.position = i;
      });
      listFrom.update();
    },
  
    addMultipleListIssues(list, issues, listFrom, newIndex) {
      let moveBeforeId = null;
      let moveAfterId = null;
  
      const listHasIssues = issues.every(issue => list.findIssue(issue.id));
  
      if (!listHasIssues) {
        if (newIndex !== undefined) {
          if (list.issues[newIndex - 1]) {
            moveBeforeId = list.issues[newIndex - 1].id;
          }
  
          if (list.issues[newIndex]) {
            moveAfterId = list.issues[newIndex].id;
          }
  
          list.issues.splice(newIndex, 0, ...issues);
        } else {
          list.issues.push(...issues);
        }
  
        if (list.label) {
          issues.forEach(issue => issue.addLabel(list.label));
        }
  
        if (list.assignee) {
          if (listFrom && listFrom.type === 'assignee') {
            issues.forEach(issue => issue.removeAssignee(listFrom.assignee));
          }
          issues.forEach(issue => issue.addAssignee(list.assignee));
        }
  
        if (IS_EE && list.milestone) {
          if (listFrom && listFrom.type === 'milestone') {
            issues.forEach(issue => issue.removeMilestone(listFrom.milestone));
          }
          issues.forEach(issue => issue.addMilestone(list.milestone));
        }
  
        if (listFrom) {
          list.issuesSize += issues.length;
  
          list.updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId);
        }
      }
    },
  
    removeListIssues(list, removeIssue) {
      list.issues = list.issues.filter(issue => {
        const matchesRemove = removeIssue.id === issue.id;
  
        if (matchesRemove) {
          list.issuesSize -= 1;
          issue.removeLabel(list.label);
        }
  
        return !matchesRemove;
      });
    },
    removeListMultipleIssues(list, removeIssues) {
      const ids = removeIssues.map(issue => issue.id);
  
      list.issues = list.issues.filter(issue => {
        const matchesRemove = ids.includes(issue.id);
  
        if (matchesRemove) {
          list.issuesSize -= 1;
          issue.removeLabel(list.label);
        }
  
        return !matchesRemove;
      });
    },
  
    startMoving(list, issue) {
      Object.assign(this.moving, { list, issue });
    },
  
    onNewListIssueResponse(list, issue, data) {
      issue.refreshData(data);
  
      if (
        !gon.features.boardsWithSwimlanes &&
        !gon.features.graphqlBoardLists &&
        list.issues.length > 1
      ) {
        const moveBeforeId = list.issues[1].id;
        this.moveIssue(issue.id, null, null, null, moveBeforeId);
      }
    },
  
    moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) {
      const issueTo = issues.map(issue => listTo.findIssue(issue.id));
      const issueLists = issues.map(issue => issue.getLists()).flat();
      const listLabels = issueLists.map(list => list.label);
      const hasMoveableIssues = issueTo.filter(Boolean).length > 0;
  
      if (!hasMoveableIssues) {
        // Check if target list assignee is already present in this issue
        if (
          listTo.type === ListType.assignee &&
          listFrom.type === ListType.assignee &&
          issues.some(issue => issue.findAssignee(listTo.assignee))
        ) {
          const targetIssues = issues.map(issue => listTo.findIssue(issue.id));
          targetIssues.forEach(targetIssue => targetIssue.removeAssignee(listFrom.assignee));
        } else if (listTo.type === 'milestone') {
          const currentMilestones = issues.map(issue => issue.milestone);
          const currentLists = this.state.lists
            .filter(list => list.type === 'milestone' && list.id !== listTo.id)
            .filter(list =>
              list.issues.some(listIssue => issues.some(issue => listIssue.id === issue.id)),
            );
  
          issues.forEach(issue => {
            currentMilestones.forEach(milestone => {
              issue.removeMilestone(milestone);
            });
          });
  
          issues.forEach(issue => {
            issue.addMilestone(listTo.milestone);
          });
  
          currentLists.forEach(currentList => {
            issues.forEach(issue => {
              currentList.removeIssue(issue);
            });
          });
  
          listTo.addMultipleIssues(issues, listFrom, newIndex);
        } else {
          // Add to new lists issues if it doesn't already exist
          listTo.addMultipleIssues(issues, listFrom, newIndex);
        }
      } else {
        listTo.updateMultipleIssues(issues, listFrom);
        issues.forEach(issue => {
          issue.removeLabel(listFrom.label);
        });
      }
  
      if (listTo.type === ListType.closed && listFrom.type !== ListType.backlog) {
        issueLists.forEach(list => {
          issues.forEach(issue => {
            list.removeIssue(issue);
          });
        });
  
        issues.forEach(issue => {
          issue.removeLabels(listLabels);
        });
      } else if (listTo.type === ListType.backlog && listFrom.type === ListType.assignee) {
        issues.forEach(issue => {
          issue.removeAssignee(listFrom.assignee);
        });
        issueLists.forEach(list => {
          issues.forEach(issue => {
            list.removeIssue(issue);
          });
        });
      } else if (listTo.type === ListType.backlog && listFrom.type === ListType.milestone) {
        issues.forEach(issue => {
          issue.removeMilestone(listFrom.milestone);
        });
        issueLists.forEach(list => {
          issues.forEach(issue => {
            list.removeIssue(issue);
          });
        });
      } else if (
        this.shouldRemoveIssue(listFrom, listTo) &&
        this.issuesAreContiguous(listFrom, issues)
      ) {
        listFrom.removeMultipleIssues(issues);
      }
    },
  
    issuesAreContiguous(list, issues) {
      // When there's only 1 issue selected, we can return early.
      if (issues.length === 1) return true;
  
      // Create list of ids for issues involved.
      const listIssueIds = list.issues.map(issue => issue.id);
      const movedIssueIds = issues.map(issue => issue.id);
  
      // Check if moved issue IDs is sub-array
      // of source list issue IDs (i.e. contiguous selection).
      return listIssueIds.join('|').includes(movedIssueIds.join('|'));
    },
  
    moveIssueToList(listFrom, listTo, issue, newIndex) {
      const issueTo = listTo.findIssue(issue.id);
      const issueLists = issue.getLists();
      const listLabels = issueLists.map(listIssue => listIssue.label);
  
      if (!issueTo) {
        // Check if target list assignee is already present in this issue
        if (
          listTo.type === 'assignee' &&
          listFrom.type === 'assignee' &&
          issue.findAssignee(listTo.assignee)
        ) {
          const targetIssue = listTo.findIssue(issue.id);
          targetIssue.removeAssignee(listFrom.assignee);
        } else if (listTo.type === 'milestone') {
          const currentMilestone = issue.milestone;
          const currentLists = this.state.lists
            .filter(list => list.type === 'milestone' && list.id !== listTo.id)
            .filter(list => list.issues.some(listIssue => issue.id === listIssue.id));
  
          issue.removeMilestone(currentMilestone);
          issue.addMilestone(listTo.milestone);
          currentLists.forEach(currentList => currentList.removeIssue(issue));
          listTo.addIssue(issue, listFrom, newIndex);
        } else {
          // Add to new lists issues if it doesn't already exist
          listTo.addIssue(issue, listFrom, newIndex);
        }
      } else {
        listTo.updateIssueLabel(issue, listFrom);
        issueTo.removeLabel(listFrom.label);
      }
  
      if (listTo.type === 'closed' && listFrom.type !== 'backlog') {
        issueLists.forEach(list => {
          list.removeIssue(issue);
        });
        issue.removeLabels(listLabels);
      } else if (listTo.type === 'backlog' && listFrom.type === 'assignee') {
        issue.removeAssignee(listFrom.assignee);
        listFrom.removeIssue(issue);
      } else if (listTo.type === 'backlog' && listFrom.type === 'milestone') {
        issue.removeMilestone(listFrom.milestone);
        listFrom.removeIssue(issue);
      } else if (this.shouldRemoveIssue(listFrom, listTo)) {
        listFrom.removeIssue(issue);
      }
    },
    shouldRemoveIssue(listFrom, listTo) {
      return (
        (listTo.type !== 'label' && listFrom.type === 'assignee') ||
        (listTo.type !== 'assignee' && listFrom.type === 'label') ||
        listFrom.type === 'backlog' ||
        listFrom.type === 'closed'
      );
    },
    moveIssueInList(list, issue, oldIndex, newIndex, idArray) {
      const beforeId = parseInt(idArray[newIndex - 1], 10) || null;
      const afterId = parseInt(idArray[newIndex + 1], 10) || null;
  
      list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId);
    },
    moveMultipleIssuesInList({ list, issues, oldIndicies, newIndex, idArray }) {
      const beforeId = parseInt(idArray[newIndex - 1], 10) || null;
      const afterId = parseInt(idArray[newIndex + issues.length], 10) || null;
      list.moveMultipleIssues({
        issues,
        oldIndicies,
        newIndex,
        moveBeforeId: beforeId,
        moveAfterId: afterId,
      });
    },
    findList(key, val, type = 'label') {
      const filteredList = this.state.lists.filter(list => {
        const byType = type
          ? list.type === type || list.type === 'assignee' || list.type === 'milestone'
          : true;
  
        return list[key] === val && byType;
      });
      return filteredList[0];
    },
    findListByLabelId(id) {
      return this.state.lists.find(list => list.type === 'label' && list.label.id === id);
    },
  
    toggleFilter(filter) {
      const filterPath = this.filter.path.split('&');
      const filterIndex = filterPath.indexOf(filter);
  
      if (filterIndex === -1) {
        filterPath.push(filter);
      } else {
        filterPath.splice(filterIndex, 1);
      }
  
      this.filter.path = filterPath.join('&');
  
      this.updateFiltersUrl();
  
      eventHub.$emit('updateTokens');
    },
  
    performSearch() {
      eventHub.$emit('performSearch');
    },
  
    setListDetail(newList) {
      this.detail.list = newList;
    },
  
    updateFiltersUrl() {
      window.history.pushState(null, null, `?${this.filter.path}`);
    },
  
    clearDetailIssue() {
      this.setIssueDetail({});
    },
  
    setIssueDetail(issueDetail) {
      this.detail.issue = issueDetail;
    },
  
    setTimeTrackingLimitToHours(limitToHours) {
      this.timeTracking.limitToHours = parseBoolean(limitToHours);
    },
  
    generateBoardGid(boardId) {
      return `gid://gitlab/Board/${boardId}`;
    },
  
    generateBoardsPath(id) {
      return `${this.state.endpoints.boardsEndpoint}${id ? `/${id}` : ''}.json`;
    },
  
    generateIssuesPath(id) {
      return `${this.state.endpoints.listsEndpoint}${id ? `/${id}` : ''}/issues`;
    },
  
    generateIssuePath(boardId, id) {
      return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${
        id ? `/${id}` : ''
      }`;
    },
  
    generateMultiDragPath(boardId) {
      return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues/bulk_move`;
    },
  
    all() {
      return axios.get(this.state.endpoints.listsEndpoint);
    },
  
    generateDefaultLists() {
      return axios.post(this.state.endpoints.listsEndpointGenerate, {});
    },
  
    createList(entityId, entityType) {
      const list = {
        [entityType]: entityId,
      };
  
      return axios.post(this.state.endpoints.listsEndpoint, {
        list,
      });
    },
  
    updateList(id, position, collapsed) {
      return axios.put(`${this.state.endpoints.listsEndpoint}/${id}`, {
        list: {
          position,
          collapsed,
        },
      });
    },
  
    updateListFunc(list) {
      const collapsed = !list.isExpanded;
      return this.updateList(list.id, list.position, collapsed).catch(() => {
        // TODO: handle request error
      });
    },
  
    destroyList(id) {
      return axios.delete(`${this.state.endpoints.listsEndpoint}/${id}`);
    },
    destroy(list) {
      const index = this.state.lists.indexOf(list);
      this.state.lists.splice(index, 1);
      this.updateNewListDropdown(list.id);
  
      this.destroyList(list.id).catch(() => {
        // TODO: handle request error
      });
    },
  
    saveList(list) {
      const entity = list.label || list.assignee || list.milestone;
      let entityType = '';
      if (list.label) {
        entityType = 'label_id';
      } else if (list.assignee) {
        entityType = 'assignee_id';
      } else if (IS_EE && list.milestone) {
        entityType = 'milestone_id';
      }
  
      return this.createList(entity.id, entityType)
        .then(res => res.data)
        .then(data => {
          list.id = data.id;
          list.type = data.list_type;
          list.position = data.position;
          list.label = data.label;
  
          return list.getIssues();
        });
    },
  
    getListIssues(list, emptyIssues = true) {
      const data = {
        ...urlParamsToObject(this.filter.path),
        page: list.page,
      };
  
      if (list.label && data.label_name) {
        data.label_name = data.label_name.filter(label => label !== list.label.title);
      }
  
      if (emptyIssues) {
        list.loading = true;
      }
  
      return this.getIssuesForList(list.id, data)
        .then(res => res.data)
        .then(data => {
          list.loading = false;
          list.issuesSize = data.size;
  
          if (emptyIssues) {
            list.issues = [];
          }
  
          data.issues.forEach(issueObj => {
            list.addIssue(new ListIssue(issueObj));
          });
  
          return data;
        });
    },
  
    getIssuesForList(id, filter = {}) {
      const data = { id };
      Object.keys(filter).forEach(key => {
        data[key] = filter[key];
      });
  
      return axios.get(mergeUrlParams(data, this.generateIssuesPath(id)));
    },
  
    moveIssue(id, fromListId = null, toListId = null, moveBeforeId = null, moveAfterId = null) {
      return axios.put(this.generateIssuePath(this.state.endpoints.boardId, id), {
        from_list_id: fromListId,
        to_list_id: toListId,
        move_before_id: moveBeforeId,
        move_after_id: moveAfterId,
      });
    },
  
    moveListIssues(list, issue, oldIndex, newIndex, moveBeforeId, moveAfterId) {
      list.issues.splice(oldIndex, 1);
      list.issues.splice(newIndex, 0, issue);
  
      this.moveIssue(issue.id, null, null, moveBeforeId, moveAfterId).catch(() => {
        // TODO: handle request error
      });
    },
  
    moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId }) {
      return axios.put(this.generateMultiDragPath(this.state.endpoints.boardId), {
        from_list_id: fromListId,
        to_list_id: toListId,
        move_before_id: moveBeforeId,
        move_after_id: moveAfterId,
        ids,
      });
    },
  
    moveListMultipleIssues({ list, issues, oldIndicies, newIndex, moveBeforeId, moveAfterId }) {
      oldIndicies.reverse().forEach(index => {
        list.issues.splice(index, 1);
      });
      list.issues.splice(newIndex, 0, ...issues);
  
      return this.moveMultipleIssues({
        ids: issues.map(issue => issue.id),
        fromListId: null,
        toListId: null,
        moveBeforeId,
        moveAfterId,
      });
    },
  
    newIssue(id, issue) {
      if (typeof id === 'string') {
        id = getIdFromGraphQLId(id);
      }
  
      return axios.post(this.generateIssuesPath(id), {
        issue,
      });
    },
  
    newListIssue(list, issue) {
      list.addIssue(issue, null, 0);
      list.issuesSize += 1;
      let listId = list.id;
      if (typeof listId === 'string') {
        listId = getIdFromGraphQLId(listId);
      }
  
      return this.newIssue(list.id, issue)
        .then(res => res.data)
        .then(data => list.onNewIssueResponse(issue, data));
    },
  
    getBacklog(data) {
      return axios.get(
        mergeUrlParams(
          data,
          `${gon.relative_url_root}/-/boards/${this.state.endpoints.boardId}/issues.json`,
        ),
      );
    },
    removeIssueLabel(issue, removeLabel) {
      if (removeLabel) {
        issue.labels = issue.labels.filter(label => removeLabel.id !== label.id);
      }
    },
  
    addIssueAssignee(issue, assignee) {
      if (!issue.findAssignee(assignee)) {
        issue.assignees.push(new ListAssignee(assignee));
      }
    },
  
    removeIssueLabels(issue, labels) {
      labels.forEach(issue.removeLabel.bind(issue));
    },
  
    bulkUpdate(issueIds, extraData = {}) {
      const data = {
        update: Object.assign(extraData, {
          issuable_ids: issueIds.join(','),
        }),
      };
  
      return axios.post(this.state.endpoints.bulkUpdatePath, data);
    },
  
    getIssueInfo(endpoint) {
      return axios.get(endpoint);
    },
  
    toggleIssueSubscription(endpoint) {
      return axios.post(endpoint);
    },
  
    recentBoards() {
      return axios.get(this.state.endpoints.recentBoardsEndpoint);
    },
  
    createBoard(board) {
      const boardPayload = { ...board };
      boardPayload.label_ids = (board.labels || []).map(b => b.id);
  
      if (boardPayload.label_ids.length === 0) {
        boardPayload.label_ids = [''];
      }
  
      if (boardPayload.assignee) {
        boardPayload.assignee_id = boardPayload.assignee.id;
      }
  
      if (boardPayload.milestone) {
        boardPayload.milestone_id = boardPayload.milestone.id;
      }
  
      if (boardPayload.id) {
        const input = {
          ...pick(boardPayload, ['hideClosedList', 'hideBacklogList']),
          id: this.generateBoardGid(boardPayload.id),
        };
  
        return Promise.all([
          axios.put(this.generateBoardsPath(boardPayload.id), { board: boardPayload }),
          gqlClient.mutate({
            mutation: createBoardMutation,
            variables: input,
          }),
        ]);
      }
  
      return axios
        .post(this.generateBoardsPath(), { board: boardPayload })
        .then(resp => resp.data)
        .then(data => {
          gqlClient.mutate({
            mutation: createBoardMutation,
            variables: {
              ...pick(boardPayload, ['hideClosedList', 'hideBacklogList']),
              id: this.generateBoardGid(data.id),
            },
          });
          return data;
        });
    },
  
    deleteBoard({ id }) {
      return axios.delete(this.generateBoardsPath(id));
    },
  
    setCurrentBoard(board) {
      this.state.currentBoard = board;
    },
  
    toggleMultiSelect(issue) {
      const selectedIssueIds = this.multiSelect.list.map(issue => issue.id);
      const index = selectedIssueIds.indexOf(issue.id);
  
      if (index === -1) {
        this.multiSelect.list.push(issue);
        return;
      }
  
      this.multiSelect.list = [
        ...this.multiSelect.list.slice(0, index),
        ...this.multiSelect.list.slice(index + 1),
      ];
    },
    removeIssueAssignee(issue, removeAssignee) {
      if (removeAssignee) {
        issue.assignees = issue.assignees.filter(assignee => assignee.id !== removeAssignee.id);
      }
    },
  
    findIssueAssignee(issue, findAssignee) {
      return issue.assignees.find(assignee => assignee.id === findAssignee.id);
    },
  
    clearMultiSelect() {
      this.multiSelect.list = [];
    },
  
    removeAllIssueAssignees(issue) {
      issue.assignees = [];
    },
  
    addIssueMilestone(issue, milestone) {
      const miletoneId = issue.milestone ? issue.milestone.id : null;
      if (IS_EE && milestone.id !== miletoneId) {
        issue.milestone = new ListMilestone(milestone);
      }
    },
  
    setIssueLoadingState(issue, key, value) {
      issue.isLoading[key] = value;
    },
  
    updateIssueData(issue, newData) {
      Object.assign(issue, newData);
    },
  
    setIssueFetchingState(issue, key, value) {
      issue.isFetching[key] = value;
    },
  
    removeIssueMilestone(issue, removeMilestone) {
      if (IS_EE && removeMilestone && removeMilestone.id === issue.milestone.id) {
        issue.milestone = {};
      }
    },
  
    refreshIssueData(issue, obj) {
      const convertedObj = convertObjectPropsToCamelCase(obj, {
        dropKeys: ['issue_sidebar_endpoint', 'real_path', 'webUrl'],
      });
      convertedObj.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
      issue.path = obj.real_path || obj.webUrl;
      issue.project_id = obj.project_id;
      Object.assign(issue, convertedObj);
  
      if (obj.project) {
        issue.project = new IssueProject(obj.project);
      }
  
      if (obj.milestone) {
        issue.milestone = new ListMilestone(obj.milestone);
        issue.milestone_id = obj.milestone.id;
      }
  
      if (obj.labels) {
        issue.labels = obj.labels.map(label => new ListLabel(label));
      }
  
      if (obj.assignees) {
        issue.assignees = obj.assignees.map(a => new ListAssignee(a));
      }
    },
    addIssueLabel(issue, label) {
      if (!issue.findLabel(label)) {
        issue.labels.push(new ListLabel(label));
      }
    },
    updateIssue(issue) {
      const data = {
        issue: {
          milestone_id: issue.milestone ? issue.milestone.id : null,
          due_date: issue.dueDate,
          assignee_ids: issue.assignees.length > 0 ? issue.assignees.map(({ id }) => id) : [0],
          label_ids: issue.labels.length > 0 ? issue.labels.map(({ id }) => id) : [''],
        },
      };
  
      return axios.patch(`${issue.path}.json`, data).then(({ data: body = {} } = {}) => {
        /**
         * Since post implementation of Scoped labels, server can reject
         * same key-ed labels. To keep the UI and server Model consistent,
         * we're just assigning labels that server echo's back to us when we
         * PATCH the said object.
         */
        if (body) {
          issue.labels = convertObjectPropsToCamelCase(body.labels, { deep: true });
        }
      });
    },
  };
  
  BoardsStoreEE.initEESpecific(boardsStore);
  
  // hacks added in order to allow milestone_select to function properly
  // TODO: remove these
  
  export function boardStoreIssueSet(...args) {
    Vue.set(boardsStore.detail.issue, ...args);
  }
  
  export function boardStoreIssueDelete(...args) {
    Vue.delete(boardsStore.detail.issue, ...args);
  }
  
  export default boardsStore;
  