// Disable no-re-export rule for entry point files
/* eslint-disable @atlaskit/editor/no-re-export */

import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
import { CellSelection } from '@atlaskit/editor-tables';
import { selectedRect } from '@atlaskit/editor-tables/utils';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../analytics';
export { RelativeSelectionPos } from './types';
export { Side } from './gap-cursor/Side';
export { GapCursorSelection, JSON_ID, GapBookmark } from './gap-cursor/selection';
export { setSelectionTopLevelBlocks, setGapCursorAtPos } from './gap-cursor/actions';
export { isIgnored } from './gap-cursor/utils/is-ignored';
export { isValidTargetNode } from './gap-cursor/utils/is-valid-target-node';
export { setGapCursorSelection } from './gap-cursor/utils/setGapCursorSelection';
export { hideCaretModifier, gapCursorStyles } from './gap-cursor/styles';
export { atTheBeginningOfDoc } from './atTheBeginningOfDoc';
export { atTheEndOfDoc } from './atTheEndOfDoc';
export { endPositionOfParent } from './endPositionOfParent';
export { expandSelectionBounds } from './expandSelectionBounds';
export { isMultiBlockRange } from './isMultiBlockRange';
export { isSelectionAtEndOfNode } from './isSelectionAtEndOfNode';
export { isSelectionAtStartOfNode } from './isSelectionAtStartOfNode';
export { startPositionOfParent } from './startPositionOfParent';
export { atTheBeginningOfBlock, atTheEndOfBlock, deleteSelectedRange, expandSelectionToBlockRange, expandToBlockRange, getSourceNodesFromSelectionRange, isMultiBlockSelection, selectionIsAtTheBeginningOfBlock } from './utils';
export { getSliceFromSelection } from './context-helpers';
export { getFragmentsFromSelection } from './getFragmentsFromSelection';
export { getLocalIdsFromSelection } from './getLocalIdsFromSelection';
export { FORMAT_SELECTION_SYNC_META } from './format-sync-meta';
export function getNodeSelectionAnalyticsPayload(selection) {
  if (selection instanceof NodeSelection) {
    return {
      action: ACTION.SELECTED,
      actionSubject: ACTION_SUBJECT.DOCUMENT,
      actionSubjectId: ACTION_SUBJECT_ID.NODE,
      eventType: EVENT_TYPE.TRACK,
      attributes: {
        node: selection.node.type.name
      }
    };
  }
}

// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
export function getAllSelectionAnalyticsPayload(selection) {
  if (selection instanceof AllSelection) {
    return {
      action: ACTION.SELECTED,
      actionSubject: ACTION_SUBJECT.DOCUMENT,
      actionSubjectId: ACTION_SUBJECT_ID.ALL,
      eventType: EVENT_TYPE.TRACK
    };
  }
}

// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
export function getCellSelectionAnalyticsPayload(state) {
  if (state.selection instanceof CellSelection) {
    const rect = selectedRect(state);
    const selectedCells = rect.map.cellsInRect(rect).length;
    const totalCells = rect.map.map.length;
    return {
      action: ACTION.SELECTED,
      actionSubject: ACTION_SUBJECT.DOCUMENT,
      actionSubjectId: ACTION_SUBJECT_ID.CELL,
      eventType: EVENT_TYPE.TRACK,
      attributes: {
        selectedCells,
        totalCells
      }
    };
  }
}

// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
export function getRangeSelectionAnalyticsPayload(selection, doc) {
  if (selection instanceof TextSelection && selection.from !== selection.to) {
    const {
      from,
      to,
      anchor,
      head
    } = selection;
    const nodes = [];
    doc.nodesBetween(from, to, (node, pos) => {
      // We want to send top-level nodes only, ie.the nodes that would have the selection styling
      // We allow text nodes that are not fully covered as they are a special case
      if (node.isText || pos >= from && pos + node.nodeSize <= to) {
        nodes.push(node.type.name);
        return false;
      }
    });
    return {
      action: ACTION.SELECTED,
      actionSubject: ACTION_SUBJECT.DOCUMENT,
      actionSubjectId: ACTION_SUBJECT_ID.RANGE,
      eventType: EVENT_TYPE.TRACK,
      attributes: {
        from: anchor,
        to: head,
        nodes
      }
    };
  }
}

/**
 * Insert content, delete a range and create a new selection
 * This function automatically handles the mapping of positions for insertion and deletion.
 * The new selection is handled as a function since it may not always be necessary to resolve a position to the transactions mapping
 *
 * @param getSelectionResolvedPos get the resolved position to create a new selection
 * @param insertions content to insert at the specified position
 * @param deletions the ranges to delete
 */

// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
export const selectNode = pos => (state, dispatch) => {
  if (dispatch) {
    dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(pos))));
  }
  return true;
};
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
export function createSelectionClickHandler(nodes, isValidTarget, options) {
  return function handleClickOn(view, _pos, node, nodePos, event, direct) {
    if (options.useLongPressSelection) {
      return false;
    }
    if (direct && nodes.indexOf(node.type.name) !== -1) {
      const target = event.target;
      if (target instanceof HTMLElement && isValidTarget(target)) {
        const selectionPos = options.getNodeSelectionPos ? options.getNodeSelectionPos(view.state, nodePos) : nodePos;
        selectNode(selectionPos)(view.state, view.dispatch);
        return true;
      }
    }
    return false;
  };
}