<script setup lang="ts">
import rfdc from "rfdc";
import type {blogMenu} from "~/drizzle/schema";
import {useAsyncData} from "nuxt/app";
const clone = rfdc()
const niMessage = useNiMessage()

const {data: obm, error} = await useFetch('/api/blog/blogMenu');
if (error.value) {
    throw error.value;
}

definePageMeta({
    layout: 'home',
    pageTransition: {
        name: 'slide',
        mode: 'out-in',
    },
})
// 菜单数据类型
type BlogMenu = typeof blogMenu.$inferInsert;
type ShowBlogMenu = BlogMenu & {
    rank?: number;
    opne?: boolean;
    openNumber?: number;
    childrenLength?: number;
}
// 菜单原始数据
const originalBlogMenuList = shallowRef<ShowBlogMenu[]>(obm as ShowBlogMenu)
// 根据pid存储列表Map
const blogMenuPidMap = ref(new Map)
// 根据id存储对象Map
const blogMenuIdMap = ref(new Map)
// blog渲染列表
const blogMenuList = ref<ShowBlogMenu[]>([]);
// blog菜单对象
const blogMenuObject = ref<ShowBlogMenu>(null);
// 选中的blog菜单对象
const activeBlogMenuObject = ref<ShowBlogMenu>(null);
// 菜单折叠
const menuCollapseStatus = ref(true)
// blog信息弹窗状态
const blogInfoPopupStatus = ref(false)
// 新增的blog菜单Pid
const insertBlogMenuPid = ref<string>('');

// ---- 数据相关
// 格式化菜单数据
const formatBlogMenuListToPidMap = (blogMenuList: Array<ShowBlogMenu>) => {
    const idMap = new Map()
    const pidMap = new Map()
    const list = clone(blogMenuList)
    const pidObj: Record<string, ShowBlogMenu[]> = {};
    for(const menuItem of list){
        if(pidObj[menuItem.pid]){
            pidObj[menuItem.pid].push(menuItem)
        }else{
            pidObj[menuItem.pid] = [menuItem]
        }
        if(menuItem.pid == 0){
            menuItem.rank = 0;
        }
        menuItem.openNumber = 0;
    }
    for(const menuItem of list){
        const id = menuItem.id;
        if(pidObj[id]){
            menuItem.childrenLength = pidObj[id].length
            consola.info(menuItem.name, menuItem.childrenLength)
        }
        idMap.set(id, menuItem)
    }
    Object.keys(pidObj).forEach(key => {
        pidMap.set(key, pidObj[key]);
    })
    blogMenuPidMap.value = pidMap
    blogMenuIdMap.value = idMap
}
// 初始化blog菜单数据
const initMenuData = () => {
    const blogMenuData = originalBlogMenuList.value
    formatBlogMenuListToPidMap(blogMenuData);
    blogMenuList.value = blogMenuPidMap.value.get('0')
}
// 客户端获取菜单数据
const getMenuListForClient = async () => {
    const resd = await $fetch('/api/blog/blogMenu').catch(e => {
        consola.warn('获取博客目录异常', e)
        niMessage.warning('获取博客目录异常!')
    });
    if(resd){
        originalBlogMenuList.value = resd;
        initMenuData()
    }
}
// 修改上级菜单的打开数量
const changeParentOpenNumber = (item: ShowBlogMenu, openNumber: number, type = '-') => {
    if(item.pid === '0'){
        item.openNumber = openNumber
        return
    }
    let targetMenuItem = item;
    while(true){
        // 获取父元素
        targetMenuItem = blogMenuIdMap.value.get(targetMenuItem.pid);
        if(type == '-'){
            targetMenuItem.openNumber -= openNumber
        }else{
            targetMenuItem.openNumber += openNumber
        }
        if(targetMenuItem.pid === '0'){
            break;
        }
    }
    if(type == '-'){
        item.openNumber = 0
    }else{
        item.openNumber = openNumber
    }
}

// --- 事件
// 展开/关闭子菜单事件
const handleCollapseChildrenEvent = (item: ShowBlogMenu, index: number) => {
    if(item.open == true){
        // 闭合
        // 将状态关闭
        blogMenuIdMap.value.get(item.id).open = false;
        // 删除子孙元素
        blogMenuList.value.splice(index + 1, item.openNumber);
        // 降低父辈元素的打开数量
        changeParentOpenNumber(item, item.openNumber, '-');
        //
    }else{
        // 展开
        // 将状态打开
        blogMenuIdMap.value.get(item.id).open = true;
        // 获取子元素
        const childrenList = blogMenuPidMap.value.get(item.id)
        blogMenuList.value.splice(index + 1, 0, ...childrenList.map(i => {
            i.rank = item.rank + 1;
            i.open = false;
            return i
        }));
        changeParentOpenNumber(item, childrenList.length, '+');
    }

}
// 新增blog事件
const handleCreateBlogMenuItemEvent = (pid: string) => {
    blogMenuObject.value = {
        pid,
        name: '',
        desc: ''
    }
    blogInfoPopupStatus.value = true;
    insertBlogMenuPid.value = pid
}
// 确认新增
const handleCreateBlogMenuItemAck = async () => {
    const resd= await $fetch('/api/blog/blogMenu',{
        method: 'POST',
        body: blogMenuObject.value
    }).catch(e => {
        consola.error(e);
        niMessage.warning('创建博客失败!');
    });
    if(resd){
        niMessage.success('创建博客成功!');
        blogInfoPopupStatus.value = false;
        const father = blogMenuIdMap.value.get(insertBlogMenuPid.value);
        resd.opne = false;
        resd.openNumber = 0;
        resd.childrenLength = 0;
        blogMenuIdMap.value.set(resd.id, resd)
        let pidMap
        if(insertBlogMenuPid.value == '0'){
            resd.rank = 0;
            pidMap = blogMenuPidMap.value.get('0')
        }else{
            resd.rank = father.rank + 1;
            father.childrenLength = father.childrenLength + 1;
            pidMap = blogMenuPidMap.value.get(father.id)
        }
        if(pidMap){
            pidMap.push(resd)
        }else{
            blogMenuPidMap.value.set(father.id, [resd])
        }
        if(father?.open){
            const openNumber = father.openNumber
            changeParentOpenNumber(father, 1, '+');
            const insertIndex = blogMenuList.value.findIndex(i => i.id === father.id)
            father.openNumber =  father.openNumber + openNumber
            blogMenuList.value.splice(insertIndex + father.openNumber, 0, resd);
        }else if(insertBlogMenuPid.value == '0'){
            blogMenuList.value = blogMenuPidMap.value.get('0')
        }
    }
}

// SSR运行
initMenuData()
onMounted(() => {
})
</script>

<template>
    <div class="homeBlog">
        <HomeBlogMenu
            class="left"
            v-model:status="menuCollapseStatus"
            v-model:active="activeBlogMenuObject"
            :blogMenuList
            @createBlogMenu="handleCreateBlogMenuItemEvent"
            @collapseChildren="handleCollapseChildrenEvent"></HomeBlogMenu>
        <div class="main">
            <header>
                <div class="menuCollapse a11 allCenter point" :class="menuCollapseStatus && 'hide'">
                    <div class="star-blogIconFont" @click="menuCollapseStatus = !menuCollapseStatus">&#xe67f;</div>
                </div>
            </header>
            <main>
                <NuxtPage />
            </main>
        </div>
        <div class="right"></div>
        <NiPopup v-model:status="blogInfoPopupStatus">
            <template #header>博客菜单</template>
            <NiForm :data="blogMenuObject">
                <NiFormItem label="博客名称" name="name" label-width="6">
                    <NiInput v-model="blogMenuObject.name"></NiInput>
                </NiFormItem>
                <NiFormItem label="博客描述" name="name" label-width="6">
                    <NiInput v-model="blogMenuObject.desc"></NiInput>
                </NiFormItem>
                <div>{{ blogMenuObject.name }}</div>
                <div>{{ blogMenuObject.desc }}</div>
            </NiForm>
            <template #footer>
                <NiButton @click="blogInfoPopupStatus = false">取消</NiButton>
                <NiButton type="primary" @click="handleCreateBlogMenuItemAck">确认</NiButton>
            </template>
        </NiPopup>
    </div>
</template>

<style scoped lang="scss">
.homeBlog {
    position: relative;
    display: flex;
    width: 100%;
    height: 100%;
    overflow: hidden;
    & > div.left{
        position: relative;
        height: 100%;
        flex-shrink: 0;
        background: var(--blog-menu-background-color);
        border-right: 1px solid var(--bg-color-be);
    }
    & > div.right{
        position: relative;
        height: 100%;
        overflow: auto;
        flex-shrink: 0;
    }
    & > div.main{
        position: relative;
        height: 100%;
        overflow: auto;
        flex: 1;
        display: flex;
        & > header{
            position: relative;
            flex-shrink: 0;
            display: flex;
            height: 3rem;
            border-bottom: 1px solid var(--bg-color-be);

            & > div.menuCollapse{
                position: relative;
                height: 100%;
                transition: width .3s;
                width: 3rem;
                overflow: hidden;
                &:hover & > div{
                    color: var(--font-color-top3-h1);
                }
                &.hide{
                    width: 0;
                }

                & > div{
                    font-size: 1.3rem;
                    color: var(--font-color-top3-h2);
                    transition: color .5s, opacity .5s;
                }
            }
        }

        & > main{
            position: relative;
            flex: 1;
            overflow: hidden;
        }
    }
}
@media (max-width: 767px){

}
@media (min-width: 768px){

}
</style>
