const LogRocket = require('logrocket');
const querystring = require('query-string');

const eachSeries = require('async/eachSeries');
const sample = require('lodash/sample');

const actions = require('./actions');
const { TIMES } = require('./constants');
const animations = require('./animations.utils');
const { infoToast, errorToast } = require('./utils');
const { tutorialVbox } = require('./tutorial.utils');

function registerEvents(store) {
    function notify(msg) {
        if (Notification && Notification.permission === 'granted') {
            const n = new Notification('MNML', {
                body: msg,
                tag: 'MNML',
            });
        }

        return infoToast(msg);
    }

    function error(msg) {
        return errorToast(msg);
    }

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

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

    function setTeam(team) {
        store.dispatch(actions.setTeam(team));
        const { nav } = store.getState();
        if (nav !== 'reshape') setNav('play');
    }

    function setSubscription(sub) {
        const { subscription } = store.getState();
        if (subscription && sub.cancel_at_period_end) {
            notify('Your subscription has been cancelled. Thank you for your support.');
        }
        store.dispatch(actions.setSubscription(sub));
    }

    function setConstructList(constructs) {
        store.dispatch(actions.setConstructs(constructs));
    }

    function setNewConstruct(construct) {
        const { constructs } = store.getState();
        constructs.push(construct);
        store.dispatch(actions.setConstructs(constructs));
    }

    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));
                store.dispatch(actions.setGameSkillInfo(null));
                // stop fetching the game state til animations are done
                const newRes = game.resolved.slice(currentGame.resolved.length);
                return eachSeries(newRes, (r, cb) => {
                    if (!r.event || r.stages === '') return cb();
                    const timeout = animations.getTime(r.stages);
                    const anims = animations.getObjects(r, game, account);
                    const text = animations.getText(r);
                    store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
                    if (anims.animSkill) store.dispatch(actions.setAnimSkill(anims.animSkill));

                    if (r.stages.includes('START_SKILL') && anims.animSource) {
                        store.dispatch(actions.setAnimSource(anims.animSource));
                    }

                    if (r.stages.includes('END_SKILL') && anims.animTarget) {
                        store.dispatch(actions.setAnimTarget(anims.animTarget));
                        if (animations.isCbAnim(anims.animSkill)) store.dispatch(actions.setAnimCb(cb));
                    }

                    if (r.stages.includes('POST_SKILL') && text) {
                        // timeout to prevent text classes from being added too soon
                        if (timeout === TIMES.POST_SKILL_DURATION_MS) {
                            store.dispatch(actions.setAnimText(text));
                        } else {
                            setTimeout(
                                () => store.dispatch(actions.setAnimText(text)),
                                timeout - TIMES.POST_SKILL_DURATION_MS
                            );
                        }
                    }

                    return setTimeout(() => {
                        store.dispatch(actions.setAnimSkill(null));
                        store.dispatch(actions.setAnimSource(null));
                        store.dispatch(actions.setAnimTarget(null));
                        store.dispatch(actions.setAnimText(null));
                        store.dispatch(actions.setAnimFocus([]));
                        if (r.stages.includes('END_SKILL') && animations.isCbAnim(anims.animSkill)) return true;
                        return cb();
                    }, timeout);
                }, err => {
                    if (err) return console.error(err);
                    // clear animation state
                    store.dispatch(actions.setAnimSkill(null));
                    store.dispatch(actions.setAnimSource(null));
                    store.dispatch(actions.setAnimTarget(null));
                    store.dispatch(actions.setAnimText(null));
                    store.dispatch(actions.setAnimating(false));
                    store.dispatch(actions.setGameEffectInfo(null));
                    store.dispatch(actions.setSkip(false));

                    // 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) {
        if (account) {
            LogRocket.init('yh0dy3/mnml');
            LogRocket.identify(account.id, account);

            if (Notification) {
                Notification.requestPermission();
            }
        }

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

    function setEmail(email) {
        store.dispatch(actions.setEmail(email));
    }

    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) {
        store.dispatch(actions.setMtxActive(null));
        return store.dispatch(actions.setInstances(v));
    }

    function setInvite(code) {
        if (!code) return store.dispatch(actions.setInvite(null));

        navigator.clipboard.writeText(code).then(() => {
            notify(`your invite code ${code} was copied to the clipboard.`);
        }, () => {});

        return store.dispatch(actions.setInvite(code));
    }

    function setInstance(v) {
        const { account, instance, ws, tutorial } = store.getState();
        if (v) {
            setInvite(null);
            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));
            }

            if (v.phase === 'Finished') {
                ws.sendAccountInstances();
            }
            if (localStorage.getItem('tutorial-complete')) {
                store.dispatch(actions.setTutorial(null));
            } else if (v.time_control === 'Practice' && v.rounds.length === 1 && tutorial) {
                tutorialVbox(player, store, tutorial);
            }
        }

        return store.dispatch(actions.setInstance(v));
    }

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

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

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

    function setDemo(d) {

        const vboxDemo = {
            players: d,
            combiner: [],
            equipped: false,
            equipping: false,
        };

        const startDemo = () => {
            const { account, itemInfo } = store.getState();
            if (account) return false;
            if (!itemInfo || itemInfo.items.length === 0) return setTimeout(startDemo, 500);
            store.dispatch(actions.setAnimTarget(null));
            const bases = ['Attack', 'Stun', 'Buff', 'Debuff', 'Block'];
            const combo = sample(itemInfo.combos.filter(i => bases.some(b => i.components.includes(b))));
            vboxDemo.combo = combo.item;
            vboxDemo.items = combo.components;
            store.dispatch(actions.setDemo(vboxDemo));


            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [0] }))), 500);
            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [0, 1] }))), 1000);
            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [0, 1, 2] }))), 1500);
            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [], items: [vboxDemo.combo, '', ''] }))), 2500);
            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [0], items: [vboxDemo.combo, '', ''], equipping: true }))), 3000);
            setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, vboxDemo, { combiner: [], items: ['', '', ''], equipped: true, equipping: false }))), 4000);

            setTimeout(() => {
                return store.dispatch(actions.setAnimTarget({
                    skill: sample(itemInfo.items.filter(i => i.skill)).item,
                    constructId: d[1].constructs[0].id,
                    player: false,
                    direction: 0,
                }));
            }, 500);

            setTimeout(() => {
                return store.dispatch(actions.setAnimTarget({
                    skill: sample(itemInfo.items.filter(i => i.skill)).item,
                    constructId: d[1].constructs[1].id,
                    player: true,
                    direction: 0,
                }));
            }, 3000);

            return setTimeout(startDemo, 5000);
        };

        startDemo();
    }

    // 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);
    // });

    /* 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

    function urlHashChange() {
        const { ws } = store.getState();
        const cmds = querystring.parse(location.hash);

        if (cmds.join) ws.sendInstanceJoin(cmds.join);
        return true;
    }

    window.addEventListener('hashchange', urlHashChange, false);

    return {
        clearCombiner,
        clearConstructRename,
        clearInfo,
        clearInstance,
        clearMtxActive,
        setAccount,
        setAccountInstances,
        setActiveItem,
        setActiveSkill,
        setChatWheel,
        setDemo,
        setConstructList,
        setNewConstruct,
        setGame,
        setEmail,
        setInstance,
        setInstanceChat,
        setItemInfo,
        setInvite,
        setPing,
        setShop,
        setTeam,
        setSubscription,
        setWs,

        urlHashChange,

        notify,
    };
}

module.exports = registerEvents;
