const preact = require('preact');
const { connect } = require('preact-redux');
const countBy = require('lodash/countBy');
const forEach = require('lodash/forEach');

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

const InfoContainer = require('./info.container');
const StashElement = require('./vbox.stash');
const StoreElement = require('./vbox.store');

const addState = connect(
    function receiveState(state) {
        const {
            ws,
            instance,
            player,
            vboxSelected,
            info,
            itemInfo,
            itemUnequip,
            tutorial,
        } = state;

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

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

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

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

        return {
            instance,
            info,
            player,
            sendVboxAccept,
            sendVboxDiscard,
            sendVboxReclaim,
            vboxSelected,
            itemInfo,
            itemUnequip,
            sendItemUnequip,
            tutorial,
        };
    },

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

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

        return {
            setInfo,
            setVboxSelected,
        };
    }
);

function validVboxSelect(vbox, itemInfo, storeSelect, stashSelect) {
    if (storeSelect.length === 0 && stashSelect.length === 0) return false;

    const validSelects = [];

    const stashItems = stashSelect.map(j => vbox.bound[j]);
    const shopItems = storeSelect.map(j => vbox.free[j[0]][j[1]]);

    const selectedItems = stashItems.concat(shopItems);
    const itemCount = countBy(selectedItems, co => co);

    itemInfo.combos.forEach(combo => {
        const comboCount = countBy(combo.components, co => co);
        const buyCount = countBy(combo.components, co => co);
        const valid = selectedItems.every(c => {
            if (!combo.components.includes(c)) return false;
            if (itemCount[c] > comboCount[c]) return false;
            buyCount[c] -= 1;
            return true;
        });
        if (valid) {
            forEach(buyCount, (value, key) => {
                if (value > 0 && !validSelects.includes(key)) validSelects.push(key);
            });
        }
    });

    return validSelects;
}

class Vbox extends preact.Component {
    shouldComponentUpdate(newProps) {
        // Single variable props
        if (newProps.itemUnequip !== this.props.itemUnequip) return true;
        if (newProps.tutorial !== this.props.tutorial) return true;
        if (newProps.vboxSelected !== this.props.vboxSelected) return true;
        if (newProps.player !== this.props.player) return true;
        if (newProps.instance !== this.props.instance) return true;
        return false;
    }

    render(args) {
        const {
            // Changing state variables
            itemUnequip,
            player,
            tutorial,
            vboxSelected,
            instance,

            // Static
            itemInfo,
            // Function Calls
            sendItemUnequip,
            sendVboxAccept,
            sendVboxDiscard,
            sendVboxReclaim,
            setVboxSelected,
            setInfo,
        } = args;

        if (!player) return false;
        const { vbox } = player;
        const { storeSelect, stashSelect } = vboxSelected;
        const vboxSelecting = storeSelect.length === 1 && stashSelect.length === 0;

        function combinerChange(newStashSelect) {
            return setVboxSelected({ storeSelect, stashSelect: newStashSelect });
        }

        const vboxHighlight = validVboxSelect(vbox, itemInfo, storeSelect, stashSelect);
        //
        // VBOX
        //
        function vboxHover(e, v) {
            if (v) {
                e.stopPropagation();
                if (storeSelect.find(c => c[0])) return true; // There is a base skill or spec selected in the vbox
                if (stashSelect.length !== 0) {
                    const base = stashSelect.find(c => !['Red', 'Blue', 'Green'].includes(vbox.bound[c]));
                    if (base || base === 0) return true;
                }
                setInfo(v);
            }
            return true;
        }

        function clearVboxSelected() {
            setVboxSelected({ storeSelect: [], stashSelect: [] });
        }

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

        function storeHdr() {
            return (
                <div class="store-hdr">
                    <h3
                        onTouchStart={e => e.target.scrollIntoView(true)}
                        onMouseOver={e => vboxHover(e, 'store')}> STORE
                    </h3>
                    <div class={`bits ${vbox.bits < 3 ? 'red' : false}`} onMouseOver={e => vboxHover(e, 'bits')}>
                        <h1> {vbox.bits}b </h1>
                    </div>
                    <button
                        class='vbox-btn'
                        onMouseOver={e => vboxHover(e, 'refill')}
                        disabled={vbox.bits < 2
                            || (tutorial && tutorial < 7
                            && instance.time_control === 'Practice' && instance.rounds.length === 1)
                        }
                        onClick={e => e.stopPropagation()}
                        onMouseDown={() => sendVboxDiscard()}>
                        refill <br />
                        2b
                    </button>
                </div>
            );
        }

        function stashHdr() {
            const refund = storeSelect.length === 0 && stashSelect.length === 1
                ? itemInfo.items.find(i => i.item === vbox.bound[stashSelect[0]]).cost
                : 0;
            const tutorialDisabled = tutorial && tutorial < 8
                && instance.time_control === 'Practice' && instance.rounds.length === 1;
            const refundBtn = (
                <button
                    disabled={tutorialDisabled || !refund}
                    class='vbox-btn'
                    onClick={e => e.stopPropagation()}
                    onMouseDown={e => {
                        e.stopPropagation();
                        sendVboxReclaim(vboxSelected.stashSelect[0]);
                    }}>
                    refund <br />
                    {refund}b
                </button>
            );

            return (
                <div class='stash-hdr'>
                    <h3 onTouchStart={e => e.target.scrollIntoView(true)}
                        onMouseOver={e => vboxHover(e, 'stash')}> STASH
                    </h3>
                    {refundBtn}
                </div>
            );
        }

        // EVERYTHING
        return (
            <div class='vbox'>
                {storeHdr()}
                {stashHdr()}
                <InfoContainer
                    vboxHighlight={vboxHighlight}
                    vboxBuySelected={vboxBuySelected}
                />
                <StoreElement
                    clearVboxSelected = {clearVboxSelected}
                    setInfo = {setInfo}
                    setVboxSelected = {setVboxSelected}
                    storeSelect = {storeSelect}
                    stashSelect = {stashSelect}
                    vbox = {vbox}
                    vboxHighlight = {vboxHighlight}
                    vboxHover = {vboxHover}
                />
                <StashElement
                    combinerChange = {combinerChange}
                    itemUnequip = {itemUnequip}
                    vbox = {vbox}
                    vboxBuySelected = {vboxBuySelected}
                    vboxHighlight = {vboxHighlight}
                    vboxHover = {vboxHover}
                    vboxSelecting = {vboxSelecting}
                    stashSelect = {stashSelect}
                    sendItemUnequip = {sendItemUnequip}
                    setInfo = {setInfo}
                    setVboxSelected = {setVboxSelected}
                />
            </div>
        );
    }
}

module.exports = addState(Vbox);
