const toast = require('izitoast');
const eachSeries = require('async/eachSeries');
const anime = require('animejs').default;

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

function registerEvents(store) {

    // timeout handlers
    store.subscribe(() => {
        const { game, instance, cryps, ws } = store.getState();

        if (!game) ws.clearGameStateTimeout();
        if (!instance) ws.clearInstanceStateTimeout();
    });


    // cryp animations
    function crypAnimations() {
        const cryps = document.querySelectorAll('img');
        if (!cryps.length) return window.requestAnimationFrame(crypAnimations);
        return anime({
            targets: 'img',
            translateX: () => anime.random(-20, 20),
            translateY: () => anime.random(0, -40),
            rotate: () => anime.random(-15, 15),
            duration: () => anime.random(5000, 6000),
            delay: () => anime.random(0, 1000),
            direction: 'alternate',
            easing: 'linear',
            loop: true,
        });
    }
    setInterval(crypAnimations, 10000);
    crypAnimations();

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

    function setCryps(cryps) {
        console.log('EVENT ->', 'cryps', cryps);
    }

    function setCrypList(cryps) {
        store.dispatch(actions.setCryps(cryps));
    }

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

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

        if (game) ws.startGameStateTimeout(game.id);
        if (game && currentGame) {
            if (game.resolved.length !== currentGame.resolved.length) {
                // stop fetching the game state til animations are done
                ws.clearGameStateTimeout();
                const newRes = game.resolved.slice(currentGame.resolved.length);
                return eachSeries(newRes, (r, cb) => {
                    if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
                    // Create sub events for combat animations
                    const sequence = getCombatSequence(r.event);
                    return eachSeries(sequence, (stage, sCb) => {
                        const stagedR = Object.create(r);
                        stagedR.stage = stage;
                        store.dispatch(actions.setResolution(stagedR));
                        return setTimeout(sCb, TIMES[stage]);
                    }, err => {
                        if (err) return console.error(err);
                        // Finished this resolution
                        return cb();
                    });
                }, err => {
                    if (err) return console.error(err);
                    store.dispatch(actions.setResolution(null));
                    // update the game
                    store.dispatch(actions.setGame(game));
                    // get the latest state and restart polling
                    ws.sendGameState(currentGame.id);
                    return true;
                });
            }
        }

        return store.dispatch(actions.setGame(game));
        // return console.log('EVENT ->', 'game', game);
    }

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

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

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

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

    function clearInfo(info) {
        store.dispatch(actions.setInfo([]));
        console.log('event clear item');
    }

    function setMenu() {
        console.log('EVENT ->', 'menu', true);
    }

    function setVbox(items) {
        console.log('EVENT ->', 'vbox', items);
    }

    function setScores(scores) {
        console.log('EVENT ->', 'scores', scores);
    }

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

    function setInstance(v) {
        const { account, ws } = store.getState();
        const player = v.players.find(p => p.id === account.id);
        if (player) store.dispatch(actions.setPlayer(player));
        if (v) ws.startInstanceStateTimeout(v.id);
        if (v.phase === 'Lobby') store.dispatch(actions.setVboxHidden(true));
        return store.dispatch(actions.setInstance(v));
    }

    function setZone(zone) {
        console.log('EVENT ->', 'zone', zone);
    }

    function setGameList(gameList) {
        console.log('EVENT ->', 'gameList', gameList);
    }

    function setCrypStatusUpdate(id, skill, target) {
        console.log('EVENT ->', 'crypStatusUpdate', { id, skill, target });
    }

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

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

    // events.on('SEND_SKILL', function skillActive(gameId, crypId, targetCrypId, skill) {
    //     ws.sendGameSkill(gameId, crypId, targetCrypId, skill);
    //     setCrypStatusUpdate(crypId, skill, targetCrypId);
    // });

    // events.on('CRYP_ACTIVE', function crypActiveCb(cryp) {
    //     for (let i = 0; i < cryps.length; i += 1) {
    //         if (cryps[i].id === cryp.id) cryps[i].active = !cryps[i].active;
    //     }
    //     return setCryps(cryps);
    // });

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

    };

    function errorPrompt(type) {
        const message = errMessages[type];
        const OK_BUTTON = '<button type="submit">OK</button>';
        toast.info({
            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,
        });
    }

    return {
        errorPrompt,
        clearCombiner,
        setAccount,
        setActiveSkill,
        setActiveVar,
        setCryps,
        setCrypList,
        setGame,
        clearInfo,
        setMenu,
        setInstance,
        setInstanceList,
        setVbox,
        setWs,
        setGameList,
        setZone,
        setPing,
        setScores,
        setVboxInfo,
    };
}

module.exports = registerEvents;
