'use strict';

let ReactDOM = require('react-dom');
let ReactDND = require('react-dnd');
let ReactHTML5Backend = require('react-dnd-html5-backend');

let DragDropContext = ReactDND.DragDropContext;
let DropTarget = ReactDND.DropTarget;
let DragSource = ReactDND.DragSource;

let {keyboardSortableContext} = require('./keyboardSortableContext');
let {keyboardSortableListItem} = require('./keyboardSortableListItem');

/**
 * @param {React.Component} Component
 * @return {function}
 */
function DndSortableListContainer(Component) {
    Component = keyboardSortableContext(Component);
    return DragDropContext(ReactHTML5Backend)(Component);
}

/**
 * @param {string} name
 * @return {function}
 */
function DndSortableListItem(name) {
    return function(Component) {
        let dropTarget = DropTarget(
            name,
            {
                hover: function(props, monitor, component) {
                    let dragItem = monitor.getItem();
                    let hoverItem = {
                        dndId: props.dndId,
                        index: props.index
                    };

                    // Don't replace items with themselves
                    if (dragItem.dndId === hoverItem.dndId) {
                        return;
                    }
                    if (props.onHover) {
                        props.onHover(
                            dragItem,
                            hoverItem,
                            isVerticalMiddleCrossed(dragItem, hoverItem, monitor, component)
                        );
                    }
                },
                drop: function(props, monitor) {
                    if (props.onMove) {
                        props.onMove(monitor.getItem().dndId, props.dndId);
                    }
                }
            },
            function(connect) {
                return {
                    connectDropTarget: connect.dropTarget()
                };
            }
        );

        let dragSource = DragSource(
            name,
            {
                beginDrag: function(props) {
                    return {
                        dndId: props.dndId,
                        index: props.index
                    };
                }
            },
            function(connect, monitor) {
                return {
                    connectDragSource: connect.dragSource(),
                    connectDragPreview: connect.dragPreview(),
                    isDragging: monitor.isDragging()
                };
            }
        );

        return keyboardSortableListItem(dropTarget(dragSource(Component)));
    };
}

function isVerticalMiddleCrossed(dragItem, hoverItem, monitor, component) {
    let result = true;

    // Determine rectangle on screen
    let hoverBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect();

    // Get vertical middle
    let hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

    // Determine mouse position
    let clientOffset = monitor.getClientOffset();

    // Get pixels to the top
    let hoverClientY = clientOffset.y - hoverBoundingRect.top;

    // Only perform the move when the mouse has crossed half of the items height
    // When dragging downwards, only move when the cursor is below 50%
    // When dragging upwards, only move when the cursor is above 50%

    // Dragging downwards
    let dragIndex = dragItem.index;
    let hoverIndex = hoverItem.index;
    if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        result = false;
    }

    // Dragging upwards
    if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        result = false;
    }

    return result;
}

exports.DndSortableListContainer = DndSortableListContainer;
exports.DndSortableListItem = DndSortableListItem;
exports.ReactDND = ReactDND;
exports.ReactHTML5Backend = ReactHTML5Backend;
