import Vue from 'vue';
import 'es6-promise/auto';
import BJ_REPORT from 'badjs-report';
import jsCookie from 'js-cookie';
import Config from './config';
import {createApp} from './main';
import ProgressBar from './components/ProgressBar.vue';
import {Promise} from 'es6-promise';


BJ_REPORT.init({
    id: Config.BADJS_ID, // 申请的项目上报ID，不指定id将不上报
    uin: jsCookie.get(Config.BADJS_COOKIE) || '', // 用户唯一标识
    combo: 1, // combo 是否合并上报， 0 关闭， 1 启动（默认）
    delay: Config.BADJS_DELAY, // 当 combo= 1 可用，延迟多少毫秒，合并缓冲区中的上报
    url: Config.BADJS_REPORT_URL, // 指定上报地址
    ignore: [/Script Error:/], // 忽略某个错误
    level: 4, // 设置默认的级别 // 上报等级 // 1-debug 2-info 4-error 8-fail
});
// 包裹异步回调
const badjs: any = BJ_REPORT;
badjs.tryJs().spyModules();
badjs.tryJs().spySystem();


// global progress bar
const bar: any = Vue.prototype.$bar = new Vue(ProgressBar).$mount();
document.body.appendChild(bar.$el);

// a global mixin that calls `asyncData` when a route component's params change
Vue.mixin({
    beforeRouteUpdate(to, from, next) {
        const resolve = () => Promise.resolve();
        const asyncData = this.$options.asyncData || resolve;
        const clientData = this.$options.clientData || resolve;
        bar.start();
        Promise.all([
            asyncData({
                store: this.$store,
                route: to,
                routeFrom: from,
            }),
            clientData({
                store: this.$store,
                route: to,
                routeFrom: from,
            }),
        ]).then(() => {
            bar.finish();
            next();
            try {
                const event = new Event('routeUpdate');
                document.dispatchEvent(event);
            } catch (err) {
            }
        }).catch(() => {
            bar.finish();
            next();
        });
    },
});

const {app, router, store} = createApp();
// store.token = jsCookie.get('server_token'); // 用于防止csrf攻击的token校验

// prime the store with server-initialized state.
// the state is determined during SSR and inlined in the page markup.
if (window.__INITIAL_STATE__) {
    store.replaceState(window.__INITIAL_STATE__);
}

// wait until router has resolved all async before hooks
// and async components...
router.onReady(() => {
    // Add router hook for handling asyncData.
    // Doing it after initial route is resolved so that we don't double-fetch
    // the data that we already have. Using router.beforeResolve() so that all
    // async components are resolved.
    router.beforeResolve((to, from, next) => {
        const matched = router.getMatchedComponents(to);
        const prevMatched = router.getMatchedComponents(from);
        let diffed = false;
        const activated = matched.filter((c, i) => {
            return diffed || (diffed = (prevMatched[i] !== c));
        });
        const clientDataHooks = activated.map((c: any) => c.options.clientData).filter(_ => _);
        const asyncDataHooks = activated.map((c: any) => c.options.asyncData).filter(_ => _);
        if (!asyncDataHooks.length && !clientDataHooks.length) {
            return next();
        }
        const dataHooks = asyncDataHooks.concat(clientDataHooks);
        bar.start();
        Promise.all(dataHooks.map(hook => hook({store, route: to, routeFrom: from})))
            .then(() => {
                bar.finish();
                next();
            })
            .catch(() => {
                bar.finish();
                next();
            });
    });
    const matchedComponents: any = router.getMatchedComponents();
    if (!window.__INITIAL_STATE__) {
        // 首屏非服务端渲染，需要自行触发数据加载逻辑
        // no matched routes
        if (!matchedComponents.length) {
            return;
        }
        Promise.all(matchedComponents.map(({options}) => options && options.asyncData && options.asyncData({
            store,
            route: router.currentRoute,
        })));
    }
    // 客户端数据触发
    matchedComponents.map(({options}) => options && options.clientData && options.clientData({
        store,
        route: router.currentRoute,
        routeFrom: null,
    }));


    // actually mount to DOM
    app.$mount('#app');
    window.app = app;
});
