import React from 'react';

// import addClass from 'reneco-utils/addClass';
import './Droppable.scss';
import DroppableHandle from './Handle';

import Model from './Model';
import Item from './Item';
import {EVENTS as RENODE_EVENTS} from 'reneco-utils/ReNode';
import dragContext, {EVENTS as DRAG_EVENTS, LAST, BASE_CLASS} from './dragContext';
// import DragOver from './DragOver';
import Placeholder from './Placeholder';
// import EmptyPlaceholder from './Empty';

export default Component => class Droppable extends React.Component {
    model = new Model({component: this});
    state = {
        list: [],
        items: [],
    };
    dragStarted = false;
    static getDerivedStateFromProps(props, state) {
        const pList = React.Children.toArray(props.children);
        if(state.list.length !== pList.length || state.list.findIndex((item, ix) => item !== pList[ix].key) > -1) {
            return {
                list: pList.map(item => item.key)
            };
        }
        return null;
    }
    initChilds() {
        this.model.updateChilds(
            React.Children.toArray(this.props.children).map(({key, props}) => ({key, props}))
        );
    }
    getNode(ix) {
        return this.state.items[ix];
    }
    getNodeByItemIX(ix) {
        return this.state.items.find(i => i.item.getIIX() === ix);
    }
    onModelChange = () => {
        const chList = React.Children.toArray(this.props.children);
        this.setState({items: this.model.childs().map(item => {
            return ({
                item,
                node: chList.find(k => k.key === item.key)
            });

        })})
    }
    onDragStart = ({over, parent, width, height, html}) => {
        this.dragStarted = true;
        console.log()
    }
    onDragEnd = e => {
        const {item, over, parent} = e || {},
            {onStructureChange} = this.props,
            {items} = this.state;
        this.dragStarted = false;
        if(this.model.getIX() === (parent && parent.getIX())) {
            const node = item.parent.getNodeByIX(item.item.getIIX());
            if(this.model.getIX() === (item && item.parent && item.parent.getIX())) {
                const prevPos = items.findIndex(i => i.item.getIIX() === item.item.getIIX()),
                    curPos = (t => t > prevPos ? t-1 : t)(over === LAST
                        ? items.length
                        : (targetIX => targetIX && items.findIndex(i => i.item.getIIX() === targetIX))(over && over.getIIX())
                    ),
                nItems = items.slice();
                nItems.splice(prevPos, 1);
                nItems.splice(curPos, 0, node);
                this.setState({items: nItems, list: nItems.map(i => i.item.key)}, () => {
                    this.model.updateChilds(nItems.map(i => ({
                        IIX: i.item.getIIX(),
                        key: i.item.key,
                        props: i.node.props
                    })), true);
                    onStructureChange && onStructureChange(nItems.map(i => i.node.props));
                });
                // console.log(nItems)
            } else {
                const curPos = over === LAST
                    ? items.length
                    : items.findIndex(i => i.item.getIIX() === over.getIIX()),
                    nItems = items.slice();
                // console.log(node);
                node.item.setParent(this.model);
                nItems.splice(curPos, 0, node);
                this.setState({items: nItems, list: nItems.map(i => i.item.key)}, () => {
                    this.model.updateChilds(nItems.map(i => ({
                        IIX: i.item.getIIX(),
                        key: i.item.key,
                        props: i.node.props
                    })), true);
                    onStructureChange && onStructureChange(nItems.map(i => i.node.props));
                });
            }
        } else if(this.model.getIX() === (item && item.parent && item.parent.getIX())) {
            const prev = items.findIndex(i => i.item.getIIX() === item.item.getIIX()),
                nItems = items.slice();
            nItems.splice(prev, 1);
            this.setState({items: nItems, list: nItems.map(i => i.item.key)}, () => {
                this.model.updateChilds(nItems.map(i => ({
                    IIX: i.item.getIIX(),
                    key: i.item.key,
                    props: i.node.props
                })), true);
                onStructureChange && onStructureChange(nItems.map(i => i.node.props));
            });
        }
    }
    onDragOver(e) {

    }
    onDragLeave(e) {
        console.log('leave');
    }
    componentDidMount() {
        // attachEvents to model
        this.model.addEventListener(RENODE_EVENTS.change, this.onModelChange);
        dragContext.addEventListener(DRAG_EVENTS.start, this.onDragStart);
        dragContext.addEventListener(DRAG_EVENTS.end, this.onDragEnd);
        this.initChilds()
    }
    // componentDidUpdate() {}
    componentWillUnmount() {
        this.model.removeEventListener(RENODE_EVENTS.change, this.onModelChange);
        dragContext.removeEventListener(DRAG_EVENTS.start, this.onDragStart);
        dragContext.removeEventListener(DRAG_EVENTS.end, this.onDragEnd);
        this.model.destruct();
        this.model = null;
    }
    componentDidUpdate(prevProps, prevState) {
        if(this.state.list.length !== prevState.list.length
            || this.state.list.findIndex((item, ix) => item !== prevState.list[ix]) > -1
        ) {
            this.initChilds();
        }
    }
    render() {
        const { horizontal, inline, exact} = this.props,
            {items} = this.state;
        return (<Component>
            {/* <div
                // onDragOver={e => this.onDragOver(e)}
            > */}
                {(items || []).map(({node, item}, ix) => (<React.Fragment key={item.getIIX()}>
                    <Placeholder parent={this.model} item={item} inline={horizontal || inline} />
                    <Item
                        inline={horizontal || inline}
                        className={`${BASE_CLASS}-item`}
                        parent={this.model}
                        item={item}
                        exact={exact}
                        next={(n => n && n.item)(items[ix + 1])}
                        // nextNext={(n => n && n.item)(items[ix + 2])}
                        key={item.getIIX()}
                    >{node}</Item>
                </React.Fragment>))}
                {/* <EmptyPlaceholder parent={this.model} /> */}
                <Placeholder parent={this.model} inline={horizontal || inline} />
            {/* </div> */}
        </Component>);
    }
}
export const Handle = DroppableHandle;