'use strict';

import ReactDOM from 'react-dom';
import ReactDND, {DragDropContext, DropTarget, DragSource} from 'react-dnd';
import ReactHTML5Backend from 'react-dnd-html5-backend';
import {keyboardSortableContext} from './keyboardSortableContext';
import {keyboardSortableListItem} from './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): any {
    return function(Component) {
        let dropTarget = DropTarget(
            name,
            {
                hover(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(props, monitor) {
                    if (props.onMove) {
                        props.onMove(monitor.getItem().dndId, props.dndId);
                    }
                }
            },
            function(connect) {
                return {
                    connectDropTarget: connect.dropTarget()
                };
            }
        );

        let dragSource = DragSource(
            name,
            {
                beginDrag(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) as any).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;
}

export {DndSortableListContainer, DndSortableListItem, ReactDND, ReactHTML5Backend};
