import { ref, toRefs, readonly } from 'vue'
import { createRouter, RouterOptions, RouteRecordRaw, RouteLocationNormalized } from 'vue-router'

interface HistoryState {
    historyStacks: RouteLocationNormalized[]; // 已访问的路由列表
    excludeViews: string[]; // 不缓存的页面
    actionName: '' | 'push' | 'replace' | 'forward' | 'back'; // 当前路由动作
    transitionName: '' | 'slide-right' | 'slide-left'; // 前进后退动画
}

export default new (class {
    private _state = ref<HistoryState>({
        historyStacks: [],
        excludeViews: [],
        actionName: '',
        transitionName: '',
    })

    /** 只读状态 */
    state;

    constructor() {
        const state = sessionStorage.getItem('historyState');
        if (state) {
            this._state.value = JSON.parse(state);
        }
        this.state = readonly(toRefs(this._state.value));
    }

    /**
     * 创建路由
     * @param options 
     * @returns 
     */
    create = (options: RouterOptions) => {
        const router = createRouter(options);
        const { push, replace, go, forward, back } = router;
        const { actionName } = toRefs(this._state.value);

        // 添加
        router.push = (to: RouteRecordRaw) => {
            actionName.value = 'push';
            return push(to);
        }

        // 替换
        router.replace = (to: RouteRecordRaw) => {
            actionName.value = 'replace';
            return replace(to);
        }

        // 前进后退
        router.go = (delta: number) => {
            if (delta > 0) {
                actionName.value = 'forward';
            }
            if (delta < 0) {
                actionName.value = 'back';
            }
            go(delta);
        }

        // 前进
        router.forward = () => {
            actionName.value = 'forward';
            forward();
        }

        // 后退
        router.back = () => {
            actionName.value = 'back';
            back();
        }

        router.beforeResolve((to) => {
            this.addHistory(to);
        })

        router.afterEach(() => {
            const { excludeViews } = toRefs(this._state.value);
            excludeViews.value = [];
        })

        return router;
    }

    /**
     * 添加历史记录
     * @param route 
     */
    private addHistory = (route: RouteLocationNormalized) => {
        const { historyStacks, excludeViews, actionName, transitionName } = toRefs(this._state.value);

        // 如果是替换动作，必定是前进
        if (actionName.value === 'replace') {
            const lastIndex = historyStacks.value.length - 1;
            const lastView = historyStacks.value[lastIndex];

            if (lastView) {
                excludeViews.value.push(lastView.name as string);
                historyStacks.value[lastIndex] = route; // 更新最后一条记录
            } else {
                historyStacks.value.push(route);
            }
            transitionName.value = 'slide-left'; // 前进动画
        } else {
            // 倒序查找路由所在的位置
            const index = (() => {
                for (let i = historyStacks.value.length - 1; i >= 0; i--) {
                    if (historyStacks.value[i].fullPath == route.fullPath) {
                        return i;
                    }
                }
                return -1;
            })();

            if (index > -1) {
                if (actionName.value === 'push') {
                    historyStacks.value.push(route);
                    transitionName.value = 'slide-left'; //前进动画
                } else {
                    if (historyStacks.value.length > 1) {
                        const i = index + 1;
                        const n = historyStacks.value.length - i;

                        excludeViews.value = historyStacks.value.map((e) => e.name).slice(-n) as string[]; // 返回数组最后位置开始的n个元素
                        historyStacks.value.splice(i, n); // 从i位置开始删除后面所有元素(包括i)
                    }
                    transitionName.value = 'slide-right'; //后退动画
                }
            } else {
                // 忽略重定向的页面
                if (!route.redirectedFrom) {
                    historyStacks.value.push(route);
                    if (historyStacks.value.length > 1) {
                        transitionName.value = 'slide-left'; // 前进动画
                    }
                }
            }
        }

        actionName.value = '';
        sessionStorage.setItem('historyState', JSON.stringify(this._state.value));
    }
})