import { DragSource, DndProvider, DropTarget } from 'react-dnd';
export { DragSource, DropTarget } from 'react-dnd';
import React, { useState, useCallback, useRef, useEffect } from 'react';
import { withStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import grey from '@material-ui/core/colors/grey';
import { color, PreviewPrompt } from '@pie-lib/render-ui';
import MultiBackend, { usePreview, MouseTransition, TouchTransition } from 'react-dnd-multi-backend';
import { TouchBackend } from 'react-dnd-touch-backend';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { renderMath } from '@pie-lib/math-rendering';
import cloneDeep from 'lodash/cloneDeep';

function _extends() {
  _extends = Object.assign || function (target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];

      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }

    return target;
  };

  return _extends.apply(this, arguments);
}

const PlaceHolder = props => {
  const {
    children,
    classes,
    className,
    isOver,
    type,
    grid,
    disabled,
    choiceBoard,
    isCategorize,
    isVerticalPool,
    minHeight
  } = props;
  const names = classNames(classes.placeholder, disabled && classes.disabled, isOver && classes.over, classes[type], className);
  const style = {};

  if (grid && grid.columns) {
    style.gridTemplateColumns = `repeat(${grid.columns}, 1fr)`;
  }

  if (grid && grid.rows) {
    const repeatValue = grid.rowsRepeatValue || '1fr';
    style.gridTemplateRows = `repeat(${grid.rows}, ${repeatValue})`;
  } // The "type" is only sent through placement-ordering / placeholder
  // It can be "choice" or "target"
  // We apply a different style for the "choice" type
  // For any other type, use a dashed black border and a white fill


  if (type === 'choice') {
    style.border = `1px solid ${color.borderLight()}`;
    style.background = color.backgroundDark();
  }

  const boardStyle = isCategorize ? classes.categorizeBoard : classes.board;
  return /*#__PURE__*/React.createElement("div", {
    style: _extends({}, style, {
      minHeight: minHeight
    }),
    className: classNames(classes.noSelectStyles, choiceBoard ? boardStyle : names, isVerticalPool && classes.verticalPool)
  }, children);
};
PlaceHolder.propTypes = {
  classes: PropTypes.object.isRequired,
  choiceBoard: PropTypes.bool,
  grid: PropTypes.shape({
    columns: PropTypes.number,
    rows: PropTypes.number,
    // if a different value then 1fr is wanted
    rowsRepeatValue: PropTypes.string
  }),
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
  className: PropTypes.string,
  isOver: PropTypes.bool,
  index: PropTypes.number,
  type: PropTypes.string,
  disabled: PropTypes.bool,
  isCategorize: PropTypes.bool,
  isVerticalPool: PropTypes.bool,
  minHeight: PropTypes.number
};

const styles$2 = theme => ({
  noSelectStyles: {
    WebkitTouchCallout: 'none',
    WebkitUserSelect: 'none',
    KhtmlUserSelect: 'none',
    MozUserSelect: 'none',
    MsUserSelect: 'none',
    userSelect: 'none'
  },
  placeholder: {
    width: '100%',
    height: '100%',
    background: color.white(),
    transition: 'background-color 200ms linear, border-color 200ms linear',
    boxSizing: 'border-box',
    display: 'grid',
    gridRowGap: `${theme.spacing.unit}px`,
    gridColumnGap: `${theme.spacing.unit}px`,
    padding: theme.spacing.unit * 1,
    border: `2px dashed ${color.black()}`
  },
  disabled: {
    boxShadow: 'none',
    background: theme.palette.background.paper
  },
  over: {
    border: `1px solid ${grey[500]}`,
    backgroundColor: `${grey[300]}`
  },
  board: {
    padding: theme.spacing.unit,
    display: 'flex',
    flexWrap: 'wrap',
    alignItems: 'center',
    minHeight: '100px',
    justifyContent: 'center',
    overflow: 'hidden',
    touchAction: 'none',
    backgroundColor: color.backgroundDark()
  },
  categorizeBoard: {
    padding: theme.spacing.unit / 2,
    display: 'flex',
    flexWrap: 'wrap',
    alignItems: 'center',
    minHeight: '100px',
    justifyContent: 'center',
    overflow: 'hidden',
    touchAction: 'none',
    backgroundColor: color.backgroundDark()
  },
  verticalPool: {
    display: 'flex',
    flexFlow: 'column wrap'
  }
});

var PlaceHolder$1 = withStyles(styles$2)(PlaceHolder);

const {
  Consumer,
  Provider
} = /*#__PURE__*/React.createContext(-1);
const generateId = () => (Math.random() * 1000001).toFixed(0);
const withUid = Component => {
  const Wrapped = props => /*#__PURE__*/React.createElement(Consumer, null, uid => /*#__PURE__*/React.createElement(Component, _extends({}, props, {
    uid: uid
  })));

  return Wrapped;
};

var uidContext = /*#__PURE__*/Object.freeze({
  __proto__: null,
  Consumer: Consumer,
  Provider: Provider,
  generateId: generateId,
  withUid: withUid
});

class Choice extends React.Component {
  render() {
    const {
      classes,
      className,
      children,
      connectDragSource
    } = this.props;
    return connectDragSource( /*#__PURE__*/React.createElement("div", {
      className: classNames(classes.choice, className)
    }, children));
  }

}
Choice.propTypes = {
  classes: PropTypes.object.isRequired,
  className: PropTypes.string,
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
  connectDragSource: PropTypes.func.isRequired
};
Choice.defaultProps = {};

const styles$1 = theme => ({
  choice: {
    backgroundColor: theme.palette.background.paper,
    border: `solid 1px ${grey[400]}`,
    padding: theme.spacing.unit,
    minHeight: '30px',
    minWidth: theme.spacing.unit * 20,
    maxWidth: theme.spacing.unit * 75
  }
});

const choiceSource = {
  canDrag(props) {
    return !props.disabled;
  },

  beginDrag(props) {
    const out = {
      choiceId: props.choice.id,
      from: props.category.id,
      alternateResponseIndex: props.alternateResponseIndex,
      choiceIndex: props.choiceIndex
    };
    return out;
  },

  endDrag: (props, monitor) => {
    if (!monitor.didDrop()) {
      const item = monitor.getItem();

      if (item.from) {
        props.onRemoveChoice(item);
      }
    }
  }
};
const styledChoice = withStyles(styles$1)(Choice);
const DraggableChoice = DragSource(({
  uid
}) => uid, choiceSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  connectDragPreview: connect.dragPreview(),
  isDragging: monitor.isDragging()
}))(styledChoice);
var choice = withUid(DraggableChoice);

const styles = {
  maskBlank: {
    // this style is applied only on small screens and for touch devices when dragging, for drag-in-the-blank.
    // It is styled to be identical to the drag-in-the-blank chip
    backgroundColor: color.white(),
    border: `1px solid ${color.text()}`,
    color: color.text(),
    alignItems: 'center',
    display: 'inline-flex',
    height: 'initial',
    minHeight: '32px',
    fontSize: 'inherit',
    whiteSpace: 'pre-wrap',
    maxWidth: '374px',
    borderRadius: '3px',
    padding: '12px'
  },
  ica: {
    backgroundColor: color.background(),
    border: `1px solid ${color.borderDark()}`,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    minHeight: '28px',
    padding: '0 3px',
    marginLeft: 2,
    marginTop: 2,
    width: 'fit-content'
  },
  categorize: {
    color: color.text(),
    backgroundColor: color.background(),
    padding: '16px',
    borderRadius: '4px',
    border: '1px solid'
  },
  matchList: {
    color: color.text(),
    backgroundColor: color.background(),
    padding: '10px',
    boxSizing: 'border-box',
    border: '1px solid #D1D1D1'
  },
  placementOrdering: {
    padding: '10px',
    boxSizing: 'border-box',
    border: '1px solid #D1D1D1',
    backgroundColor: color.background()
  }
};

const getPrompt = (itemType, item) => {
  var _item$choice;

  switch (itemType) {
    // DRAG-IN-THE-BLANK
    case 'MaskBlank':
      return item == null ? void 0 : (_item$choice = item.choice) == null ? void 0 : _item$choice.value;
    // IMAGE-CLOZE-ASSOCIATION

    case 'react-dnd-response':
      return item == null ? void 0 : item.value;
    // MATCH-LIST

    case 'Answer':
      return item == null ? void 0 : item.value;
    // PLACEMENT-ORDERING

    case 'Tile':
      return item == null ? void 0 : item.value;

    default:
      return (item == null ? void 0 : item.itemType) === 'categorize' ? item == null ? void 0 : item.value : undefined;
  }
};

const getCustomStyle = (itemType, item, touchPosition, style) => {
  const transform = `translate(${touchPosition.x}px, ${touchPosition.y}px)`;
  const top = (style == null ? void 0 : style.top) || 0;
  const left = (style == null ? void 0 : style.left) || 0;
  const position = (style == null ? void 0 : style.position) || 'fixed';
  return _extends({
    position,
    top,
    left,
    transform
  }, itemType === 'MaskBlank' ? styles.maskBlank : {}, (item == null ? void 0 : item.itemType) === 'categorize' ? styles.categorize : {}, itemType === 'Answer' ? styles.matchList : {}, itemType === 'Tile' ? styles.placementOrdering : {}, itemType === 'react-dnd-response' ? styles.ica : {});
};

const PreviewComponent = () => {
  var _item$choice2;

  const preview = usePreview();
  const {
    itemType,
    item,
    style,
    display
  } = preview;
  const [touchPosition, setTouchPosition] = useState({
    x: 0,
    y: 0
  });
  const [zoomLevel, setZoomLevel] = useState(1);
  const handleTouchMove = useCallback(event => {
    if (event.touches.length > 0) {
      const touch = event.touches[0];
      const touchOffset = 1;
      setTouchPosition({
        x: (touch.clientX + touchOffset) / zoomLevel,
        y: (touch.clientY + touchOffset) / zoomLevel
      });
    }
  }, [zoomLevel]);
  const root = useRef(null);
  useEffect(() => {
    if (display && root.current) {
      renderMath(root.current); // Adjusted for precise zoom level calculation in Online Testing, targeting the specific class pattern .asmt-zoomable.asmt-zoom-NR .asmt-question .padding

      const zoomAffectedElement = document.querySelector('.padding') || document.body;
      setZoomLevel(parseFloat(getComputedStyle(zoomAffectedElement).zoom) || 1);
    }
  }, [display, item == null ? void 0 : (_item$choice2 = item.choice) == null ? void 0 : _item$choice2.value, item == null ? void 0 : item.value, itemType, item]);
  useEffect(() => {
    const touchMoveListener = event => handleTouchMove(event);

    if (display) {
      window.addEventListener('touchmove', touchMoveListener);
    }

    return () => {
      window.removeEventListener('touchmove', touchMoveListener);
    };
  }, [display, handleTouchMove]);

  if (!display) {
    return null;
  }

  const customStyle = getCustomStyle(itemType, item, touchPosition, style);
  const prompt = getPrompt(itemType, item);
  return /*#__PURE__*/React.createElement("div", {
    ref: root,
    style: customStyle
  }, /*#__PURE__*/React.createElement(PreviewPrompt, {
    className: "label",
    prompt: prompt,
    tagName: "span"
  }));
};

const backends = [{
  backend: HTML5Backend,
  transition: MouseTransition
}, {
  backend: TouchBackend,
  options: {
    enableMouseEvents: true,
    enableTouchEvents: true
  },
  preview: true,
  transition: TouchTransition,
  skipDispatchOnTransition: true
}];
var withDragContext = (Component => props => {
  const isClient = typeof window !== 'undefined';
  return /*#__PURE__*/React.createElement(DndProvider, _extends({
    backend: MultiBackend,
    options: {
      backends
    }
  }, isClient && {
    context: window
  }), /*#__PURE__*/React.createElement(Component, props), /*#__PURE__*/React.createElement(PreviewComponent, null));
});

var swap = ((arr, fromIndex, toIndex) => {
  if (!arr || arr.length <= 1 || fromIndex === undefined || toIndex === undefined) {
    throw new Error(`swap requires a non-empty array, fromIndex, toIndex: ${arr}, ${fromIndex} ${toIndex}`);
  }

  const update = cloneDeep(arr);
  const tmp = arr[toIndex];
  update[toIndex] = update[fromIndex];
  update[fromIndex] = tmp;
  return update;
});

const preventInteractionStyle = {
  flex: 1
};
class DroppablePlaceholder extends React.Component {
  render() {
    const {
      children,
      connectDropTarget,
      isOver,
      disabled,
      classes,
      isVerticalPool,
      minHeight
    } = this.props;
    return connectDropTarget( /*#__PURE__*/React.createElement("div", {
      style: preventInteractionStyle
    }, /*#__PURE__*/React.createElement(PlaceHolder$1, {
      disabled: disabled,
      isOver: isOver,
      choiceBoard: true,
      className: classes,
      isVerticalPool: isVerticalPool,
      minHeight: minHeight
    }, children)));
  }

}
DroppablePlaceholder.propTypes = {
  classes: PropTypes.object,
  connectDropTarget: PropTypes.func.isRequired,
  isOver: PropTypes.bool,
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
  disabled: PropTypes.bool,
  isVerticalPool: PropTypes.bool,
  minHeight: PropTypes.number
};

var dragType = {
  types: {
    ica: 'react-dnd-response',
    ml: 'Answer',
    db: 'MaskBlank'
  }
};

const spec$2 = {
  canDrop: props => {
    return !props.disabled;
  },
  drop: (props, monitor) => {
    const item = monitor.getItem();

    if (props.onRemoveAnswer) {
      props.onRemoveAnswer(item.promptId);
    }
  }
};
const WithTarget$2 = DropTarget(dragType.types.ml, spec$2, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver()
}))(DroppablePlaceholder);

const spec$1 = {
  canDrop: props => {
    return !props.disabled;
  },
  drop: () => ({
    dropped: true
  })
};
const WithTarget$1 = DropTarget(dragType.types.db, spec$1, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver()
}))(DroppablePlaceholder);

const spec = {
  canDrop: props => {
    return !props.disabled;
  },
  drop: (props, monitor) => {
    const item = monitor.getItem();

    if (props.onRemoveAnswer) {
      props.onRemoveAnswer(item);
    }
  }
};
const WithTarget = DropTarget(dragType.types.ica, spec, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver()
}))(DroppablePlaceholder);

export { choice as Choice, WithTarget$1 as DragDroppablePlaceholder, WithTarget as ICADroppablePlaceholder, WithTarget$2 as MatchDroppablePlaceholder, PlaceHolder$1 as PlaceHolder, swap, uidContext as uid, withDragContext };
//# sourceMappingURL=index.js.map
