const toast = require('izitoast');
const eachSeries = require('async/eachSeries');

const actions = require('./actions');
const { TIMES } = require('./constants');
const animations = require('./animations.utils');

function registerEvents(store) {
    function setPing(ping) {
        store.dispatch(actions.setPing(ping));
    }

    function setTeam(team) {
        localStorage.setItem('team', JSON.stringify(team));
        store.dispatch(actions.setTeam(team));
    }

    function setNav(v) {
        store.dispatch(actions.setNav(v));
    }

    function setConstructList(constructs) {
        // check team is in list
        const { team } = store.getState();
        const ids = constructs.map(c => c.id);

        // team is fucked up, or just registered
        // reset to the first 3 constructs
        if (!team.every(t => t && ids.includes(t))) {
            setTeam([ids[0], ids[1], ids[2]]);
        }

        store.dispatch(actions.setConstructs(constructs));
    }

    function setInstanceList(list) {
        store.dispatch(actions.setInstanceList(list));
    }

    function setWs(ws) {
        store.dispatch(actions.setWs(ws));
    }

    function setGame(game) {
        const { game: currentGame, account, ws, animating } = store.getState();

        if (animating) return false;

        if (game && currentGame) {
            if (game.resolved.length !== currentGame.resolved.length) {
                store.dispatch(actions.setAnimating(true));

                // stop fetching the game state til animations are done
                const newRes = game.resolved.slice(currentGame.resolved.length);
                return eachSeries(newRes, (r, cb) => {
                    if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();

                    // convert server enum into anims keywords
                    // todo make serersideonly
                    const sequence = animations.getSequence(r);
                    const timeout = animations.getTime(sequence);
                    const anims = animations.getObjects(r, sequence, game, account);
                    const text = animations.getText(r, sequence);

                    store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));

                    if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource));
                    if (sequence.includes('END_SKILL')) {
                        store.dispatch(actions.setAnimTarget(anims.animTarget));
                        if (!['Banish', 'Invert'].includes(anims.animTarget.skill)) store.dispatch(actions.setAnimCb(cb));
                    }
                    if (sequence.includes('POST_SKILL')) {
                        // timeout to prevent text classes from being added too soon
                        setTimeout(
                            () => store.dispatch(actions.setAnimText(text)),
                            timeout - TIMES.POST_SKILL_DURATION_MS
                        );
                    }
                    return setTimeout(() => {
                        store.dispatch(actions.setAnimSource(null));
                        store.dispatch(actions.setAnimTarget(null));
                        store.dispatch(actions.setAnimText(null));
                        store.dispatch(actions.setAnimFocus([]));
                        if (!sequence.includes('END_SKILL')
                            || ['Banish', 'Invert'].includes(anims.animTarget.skill)) return cb();
                        return true;
                    }, timeout);
                }, err => {
                    if (err) return console.error(err);
                    // clear animation state
                    store.dispatch(actions.setAnimSource(null));
                    store.dispatch(actions.setAnimTarget(null));
                    store.dispatch(actions.setAnimText(null));
                    store.dispatch(actions.setAnimating(false));

                    store.dispatch(actions.setSkip(false));
                    store.dispatch(actions.setResolution(null));

                    // set the game state so resolutions don't fire twice
                    store.dispatch(actions.setGame(game));
                    ws.sendGameState(game.id);
                    return true;
                });
            }
        }

        return store.dispatch(actions.setGame(game));
    }

    function setAccount(account) {
        store.dispatch(actions.setAccount(account));
    }

    function setShop(v) {
        store.dispatch(actions.setShop(v));
    }

    function clearCombiner() {
        store.dispatch(actions.setInfo([]));
        store.dispatch(actions.setCombiner([]));
    }

    function clearConstructRename() {
        store.dispatch(actions.setConstructRename(null));
    }

    function clearMtxActive() {
        store.dispatch(actions.setMtxActive(null));
    }

    function setActiveSkill(skill) {
        store.dispatch(actions.setActiveSkill(skill));
    }

    function setActiveItem(v) {
        store.dispatch(actions.setActiveItem(v));
    }

    function clearInfo() {
        store.dispatch(actions.setInfo(null));
        store.dispatch(actions.setActiveConstruct(null));
        console.log('event clear item');
    }

    function clearInstance() {
        store.dispatch(actions.setCombiner([]));
        store.dispatch(actions.setReclaiming(false));
        store.dispatch(actions.setActiveSkill(null));
        store.dispatch(actions.setActiveConstruct(null));
        store.dispatch(actions.setInfo(null));
        store.dispatch(actions.setItemEquip(null));
        store.dispatch(actions.setItemUnequip([]));
        store.dispatch(actions.setVboxHighlight([]));
    }

    function setAccountInstances(v) {
        return store.dispatch(actions.setInstances(v));
    }

    function setInstance(v) {
        const { account, ws, instance } = store.getState();
        if (v) {
            const player = v.players.find(p => p.id === account.id);
            store.dispatch(actions.setPlayer(player));

            if (!instance || v.id !== instance.id) {
                store.dispatch(actions.setNav('vbox'));
                const first = player.constructs[0];
                store.dispatch(actions.setActiveConstruct(first));
            }
        }
        return store.dispatch(actions.setInstance(v));
    }

    function setItemInfo(v) {
        return store.dispatch(actions.setItemInfo(v));
    }

    // events.on('SET_PLAYER', setInstance);

    // events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) {
    //     ws.sendGameSkill(gameId, constructId, targetConstructId, skill);
    //     setConstructStatusUpdate(constructId, skill, targetConstructId);
    // });

    // events.on('CONSTRUCT_ACTIVE', function constructActiveCb(construct) {
    //     for (let i = 0; i < constructs.length; i += 1) {
    //         if (constructs[i].id === construct.id) constructs[i].active = !constructs[i].active;
    //     }
    //     return setConstructs(constructs);
    // });

    const errMessages = {
        select_constructs: 'Select your constructs before battle using the numbered buttons next to the construct avatar',
        complete_nodes: 'You need to complete the previously connected nodes first',
        max_skills: 'Your construct can only learn a maximum of 4 skills',

    };

    function errorPrompt(type) {
        const message = errMessages[type];
        const OK_BUTTON = '<button type="submit">OK</button>';
        toast.error({
            theme: 'dark',
            color: 'black',
            timeout: false,
            drag: false,
            position: 'center',
            maxWidth: window.innerWidth / 2,
            close: false,
            buttons: [
                [OK_BUTTON, (instance, thisToast) => instance.hide({ transitionOut: 'fadeOut' }, thisToast)],
            ],
            message,
        });
    }

    // setup / localstorage
    const team = JSON.parse(localStorage.getItem('team'));
    if (team && team.every(t => t)) {
        setTeam(team);
        setNav('list');
    }

    return {
        clearCombiner,
        clearConstructRename,
        clearInfo,
        clearInstance,
        clearMtxActive,
        errorPrompt,
        setAccount,
        setAccountInstances,
        setActiveItem,
        setActiveSkill,
        setConstructList,
        setGame,
        setInstance,
        setInstanceList,
        setItemInfo,
        setPing,
        setShop,
        setWs,
    };
}

module.exports = registerEvents;
