const preact = require('preact');
const range = require('lodash/range');
const without = require('lodash/without');
const { connect } = require('preact-redux');

const shapes = require('./shapes');
const actions = require('../actions');

const addState = connect(
    function receiveState(state) {
        const {
            ws,
            instance,
            player,
            combiner,
            reclaiming,
            vboxHighlight,
            vboxSelected,
            itemInfo,
            itemUnequip,
        } = state;

        function sendVboxDiscard() {
            return ws.sendVboxDiscard(instance.id);
        }

        function sendVboxAccept(group, index) {
            return ws.sendVboxAccept(instance.id, group, index);
        }

        function sendVboxCombine() {
            return ws.sendVboxCombine(instance.id, combiner);
        }

        function sendVboxReclaim(i) {
            return ws.sendVboxReclaim(instance.id, i);
        }

        function sendItemUnequip([constructId, item]) {
            return ws.sendVboxUnequip(instance.id, constructId, item);
        }

        return {
            combiner,
            instance,
            player,
            reclaiming,
            sendVboxAccept,
            sendVboxCombine,
            sendVboxDiscard,
            sendVboxReclaim,
            vboxHighlight,
            vboxSelected,
            itemInfo,
            itemUnequip,
            sendItemUnequip
        };
    },

    function receiveDispatch(dispatch) {
        function setCombiner(c) {
            return dispatch(actions.setCombiner(c));
        }

        function setReclaiming(v) {
            return dispatch(actions.setReclaiming(v));
        }

        function setInfo(item) {
            return dispatch(actions.setInfo(item));
        }

        function setVboxHighlight(v) {
            return dispatch(actions.setVboxHighlight(v));
        }

        function setVboxSelected(v) {
            return dispatch(actions.setVboxSelected(v));
        }

        function setItemEquip(v) {
            return dispatch(actions.setItemEquip(v));
        }

        return {
            setCombiner,
            setReclaiming,
            setInfo,
            setVboxHighlight,
            setVboxSelected,
            setItemEquip,
        };
    }

);

function Vbox(args) {
    const {
        combiner,
        // instance,
        itemInfo,
        player,
        reclaiming,
        sendVboxAccept,
        sendVboxCombine,
        sendVboxDiscard,
        sendVboxReclaim,
        // vboxHighlight,

        setCombiner,
        setInfo,

        vboxSelected,
        setVboxSelected,

        setItemEquip,
        itemUnequip,
        sendItemUnequip,

        setReclaiming,
        setVboxHighlight,
    } = args;

    if (!player) return false;
    const { vbox } = player;
    const vboxSelecting = vboxSelected.length;

    // function setHighlight(type) {
    //     if (type === 'skill') return setVboxHighlight(itemInfo.items.filter(v => v.skill).map(v => v.item));
    //     if (type === 'spec') return setVboxHighlight(itemInfo.items.filter(v => v.spec).map(v => v.item));
    //     return false;
    // }

    function combinerChange(newCombiner) {
        setCombiner(newCombiner);

        if (newCombiner.length === 1) {
            setItemEquip(newCombiner[0]);
        } else {
            setItemEquip(null);
        }

        if (newCombiner.every(c => c === null)) return setVboxHighlight([]);

        const combinerValues = newCombiner.map(cv => player.vbox.bound[cv]).filter(cv => cv);

        const filteredCombos = itemInfo.combos
            .filter(combo => combinerValues.every(u => combo.components.includes(u)));

        const comboValues = itemInfo.items.filter(v => {
            if (!filteredCombos.some(c => c.components.includes(v.item))) return false;
            if (!['Red', 'Green', 'Blue'].includes(v.item) && combinerValues.includes(v.item)) return false;
            return true;
        });

        return setVboxHighlight(comboValues.map(v => v.item));
    }

    //
    // VBOX
    //
    function vboxHover(e, v) {
        if (v) {
            setInfo(v);
            e.stopPropagation();
        }
        return true;
    }

    function clearVboxSelected() {
        setVboxSelected([]);
    }

    function vboxBuySelected() {
        if (!vboxSelecting) return false;
        document.activeElement.blur();
        clearVboxSelected();
        sendVboxAccept(vboxSelected[0], vboxSelected[1]);
        return true;
    }

    function availableBtn(v, group, index) {
        if (!v) return <button disabled class='empty' >&nbsp;</button>;

        const selected = vboxSelected[0] === group && vboxSelected[1] === index;

        // state not yet set in double click handler
        function onDblClick(e) {
            sendVboxAccept(group, index);
            e.stopPropagation();
        }

        function onClick(e) {
            e.stopPropagation();
            if (selected) return clearVboxSelected();
            return setVboxSelected([group, index]);
        }

        const classes = `${selected ? 'highlight' : ''}`;

        if (shapes[v]) {
            return (
                <button
                    class={classes}
                    onMouseOver={e => vboxHover(e, v)}
                    onMouseDown={onClick}
                    onDblClick={onDblClick} >
                    {shapes[v]()}
                </button>
            );
        }

        return (
            <button
                class={classes}
                onMouseDown={onClick}
                onDblClick={onDblClick}
                onMouseOver={e => vboxHover(e, v)}>
                {v}
            </button>
        );
    }


    function vboxElement() {
        return (
            <div class='vbox-vbox'
                onMouseDown={() => setReclaiming(false)}
                onMouseOver={e => hoverInfo(e, 'vbox')}>
                <div class="vbox-hdr">
                    <h3 onTouchStart={e => e.target.scrollIntoView(true)}>VBOX</h3>
                    <div class="bits" onMouseOver={e => hoverInfo(e, 'bits')} >{vbox.bits}b</div>
                </div>
                <div class="vbox-colours">
                    {range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))}
                </div>
                <div class="vbox-items">
                    {range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))}
                    {range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))}
                </div>
                <button
                    class='vbox-btn'
                    onMouseOver={e => hoverInfo(e, 'refill')}
                    onMouseDown={() => sendVboxDiscard()}>
                    refill - 2b
                </button>
            </div>
        );
    }

    //
    //  INVENTORY
    //

    // const boundTds = range(0, 9).map(i => {
    //     const value = vbox.bound[i];
    //     if (combiner.indexOf(i) > -1) {
    //         return (
    //             <td
    //                 key={i}>
    //                 &nbsp;
    //             </td>
    //         );
    //     }

    //     const highlighted = value && vboxHighlight.includes(value);

    //     return (
    //         <td
    //             key={i}
    //             class={`${highlighted ? 'highlight' : ''}`}
    //             onMouseOver={(e) => vboxHover(e, value)}
    //             onMouseDown={e => boundClick(e, i, highlighted) }>
    //             {convertItem(value)}
    //         </td>
    //     );
    // });


    function reclaimClick(e) {
        e.stopPropagation();
        return setReclaiming(!reclaiming);
    }

    const inventoryClass = `vbox-section ${reclaiming ? 'reclaiming' : ''}`;

    function inventoryBtn(v, i) {
        const inventoryHighlight = vboxSelecting || itemUnequip.length;

        if (!v && v !== 0) {
            return <button disabled={!inventoryHighlight} class={inventoryHighlight ? 'receiving' : 'empty'} >&nbsp;</button>;
        }

        function onClick(e) {
            if (reclaiming) return sendVboxReclaim(i);

            const combinerIndex = combiner.indexOf(i);
            if (combinerIndex > -1) {
                return combinerChange(without(combiner, i));
            }

            combiner.push(i);
            return combinerChange(combiner);
        }

        const highlighted = combiner.indexOf(i) > -1;
        const classes = `${highlighted ? 'highlight' : ''}`;
        if (shapes[v]) {
            return (
                <button
                    class={classes}
                    onMouseOver={e => vboxHover(e, v)}
                    onMouseDown={onClick}>
                    {shapes[v]()}
                </button>
            );
        }

        return (
            <button
                class={classes}
                onMouseDown={onClick}
                onMouseOver={e => vboxHover(e, v)}>
                {v}
            </button>
        );
    }

    function combinerBtn() {
        let text = '';

        if (combiner.length < 3) {
            for (let i = 0; i < 3; i++) {
                if (combiner.length > i) {
                    text += '■ ';
                } else {
                    text += '▫ ';
                }
            }
        } else {
            text = 'combine';
        }

        return (
            <button
                class='vbox-btn'
                disabled={combiner.length !== 3}
                onMouseOver={e => hoverInfo(e, 'refine')}
                onMouseDown={() => sendVboxCombine()}>
                {text}
            </button>
        );
    }

    function inventoryElement() {
        function inventoryClick(e) {
            e.stopPropagation();
            setReclaiming(false);
            if (vboxSelecting) return vboxBuySelected();
            if (itemUnequip.length) return sendItemUnequip(itemUnequip);
            return true;
        }

        return (
            <div class={inventoryClass}
                onMouseDown={inventoryClick}
                style={vboxSelecting || itemUnequip.length ? { cursor: 'pointer' } : null}
                onMouseOver={e => hoverInfo(e, 'inventory')}>
                <div class="vbox-hdr">
                    <h3 onTouchStart={e => e.target.scrollIntoView(true)}>INVENTORY</h3>
                    <button
                        class='vbox-btn reclaim'
                        onMouseOver={e => hoverInfo(e, 'reclaim')}
                        onMouseDown={reclaimClick}>
                        reclaim
                    </button>
                </div>
                <div class='vbox-items'>
                    {range(0, 9).map(i => inventoryBtn(vbox.bound[i], i))}
                </div>
                {combinerBtn()}
            </div>
        );
    }

    //
    // EVERYTHING
    //
    function hoverInfo(e, info) {
        e.stopPropagation();
        return setInfo(info);
    }

    const classes = 'vbox';
    return (
        <div class={classes}>
            {vboxElement()}
            <div class="vbox-arrow">⮞</div>
            {inventoryElement()}
        </div>
    );
}

module.exports = addState(Vbox);
