<template>
    <SelectFolder :rootPath="rootFolderPath" :nodeDataCallback="appendDataForNode" @update:rootPath="changeRootPath"
        @folder-selected="showFileTree" />
    <FolderTree ref="folderTreeRef" :treeData="folderTreeData" :expandLevel="1" :selectedNode="[currentFilePath]"
        :specifyFileSuffix="['md']" @file-selected="fileSelected" />
</template>

<script setup>
import SelectFolder from './UI/SelectFolder.vue';
import FolderTree from './UI/FolderTree.vue';
import { ref } from 'vue';
import { mkdir, remove, create, exists, rename } from '@tauri-apps/plugin-fs';
import { Message } from 'view-ui-plus'

defineProps({
    currentFilePath: {
        type: String,
        required: false,
        default: ''
    },
    rootFolderPath: {
        type: String,
        required: false,
        default: ''
    },
});

const emit = defineEmits([
    'update:currentFilePath',
    'update:rootFolderPath'
]);

const folderTreeRef = ref(null)
// <SelectFolder> 返回的文件树数据，增加自定义数据，便于传给 <FolderTree> 进行渲染
function appendDataForNode(nodeData) {
    if (nodeData.directory) {
        // 当前节点为文件夹，增加“新建目录”“新建文件”等右键菜单
        nodeData.contextMenuData = [
            {
                name: "新建目录",
                handler: (nodeRenderData) => {
                    // 新建子节点时自动展开当前文件夹
                    nodeRenderData.expand = true;
                    // 定义子节点为 input 输入框
                    let subNodeData = {
                        input: true,
                        completer: async (data, newName) => {
                            newName = newName.trim();
                            // 如果输入名称为空，则取消当前节点
                            if (newName.length == 0) {
                                folderTreeRef.value.removeTreeNode(data);
                                return;
                            }
                            // 文件名不能包含 / 符号
                            if (newName.indexOf('/') >= 0) {
                                Message.error('不能包含 / 符号');
                                folderTreeRef.value.removeTreeNode(data);
                                return;
                            }
                            let createSubNodeOfParent = false;
                            // 输入名称不为空，尝试在该目录下新建子节点
                            try {
                                const newPath = nodeData.path + '/' + newName;
                                data.sourceData.path = newPath;
                                data.sourceData.name = newName;
                                // 给新增的子节点也执行 appendDataForNode 操作
                                appendDataForNode(data.sourceData);
                                // 重新渲染当前节点
                                if (folderTreeRef.value.reRenderTreeNode(data) === false) {
                                    throw new Error("变更文件树失败");
                                }
                                createSubNodeOfParent = true;
                                // 最后再尝试操作系统创建目录
                                await mkdir(newPath);
                                Message.success('创建目录成功: ' + newPath);
                            } catch (err) {
                                Message.error('创建目录失败: ' + err);
                                // 如果最后操作系统接口失败，需要回滚文件树新增的节点
                                if (createSubNodeOfParent) {
                                    folderTreeRef.value.removeTreeNode(data);
                                }
                            }
                        },
                        path: "", // 留空，在 completer 中填充
                        name: "", // 留空，在 completer 中填充
                        directory: true, // 当前新建的是目录，所以为 true
                    };
                    // 将子节点挂载到文件树上，在当前目录之下
                    folderTreeRef.value.appendTreeNode(nodeRenderData, subNodeData);
                }
            },
            {
                name: "新建文件",
                handler: (nodeRenderData) => {
                    // 新建子节点时自动展开当前文件夹
                    nodeRenderData.expand = true;
                    // 定义子节点为 input 输入框
                    let subNodeData = {
                        input: true,
                        completer: async (data, newName) => {
                            newName = newName.trim();
                            // 如果输入名称为空，则取消当前节点
                            if (newName.length == 0) {
                                folderTreeRef.value.removeTreeNode(data);
                                return;
                            }
                            // 文件名不能包含 / 符号
                            if (newName.indexOf('/') >= 0) {
                                Message.error('不能包含 / 符号');
                                folderTreeRef.value.removeTreeNode(data);
                                return;
                            }
                            // 如果文件不以 .md 为后缀，同样取消当前输入框
                            if (!newName.endsWith('.md')) {
                                Message.error('只允许 .md 文件');
                                folderTreeRef.value.removeTreeNode(data);
                                return;
                            }
                            let createSubNodeOfParent = false;
                            // 输入名称不为空，尝试在该目录下新建子节点
                            try {
                                const newPath = nodeData.path + '/' + newName;
                                // 检查新的路径是否已存在，避免覆盖其他文件
                                const exist = await exists(newPath);
                                if (exist) {
                                    // 恢复当前节点并报错
                                    folderTreeRef.value.removeTreeNode(data);
                                    throw new Error("存在同名文件.");
                                }
                                data.sourceData.path = newPath;
                                data.sourceData.name = newName;
                                // 给新增的子节点也执行 appendDataForNode 操作
                                appendDataForNode(data.sourceData);
                                // 重新渲染当前节点
                                if (folderTreeRef.value.reRenderTreeNode(data) === false) {
                                    throw new Error("变更文件树失败");
                                }
                                createSubNodeOfParent = true;
                                // 最后再尝试操作系统创建目录
                                await create(newPath);
                                Message.success('创建文件成功: ' + newPath);
                            } catch (err) {
                                Message.error('创建文件失败: ' + err);
                                // 如果最后操作系统接口失败，需要回滚文件树新增的节点
                                if (createSubNodeOfParent) {
                                    folderTreeRef.value.removeTreeNode(data);
                                }
                            }
                        },
                        path: "", // 留空，在 completer 中填充
                        name: "", // 留空，在 completer 中填充
                        directory: false, // 当前新建的是文件，所以为 false
                    };
                    // 将子节点挂载到文件树上，在当前目录之下
                    folderTreeRef.value.appendTreeNode(nodeRenderData, subNodeData);
                }
            },
            {
                name: "删除",
                handler: async (nodeRenderData) => {
                    try {
                        if (folderTreeRef.value.removeTreeNode(nodeRenderData) === false) {
                            throw new Error("变更文件树失败");
                        }
                        await remove(nodeRenderData.path, { recursive: true });
                        Message.success('删除目录成功: ' + nodeRenderData.path);
                    } catch (err) {
                        Message.error('删除目录失败: ' + err);
                    }
                }
            }
        ];
    } else {
        // 给文件节点，增加 suffix 字段，用于表示文件后缀，便于 <FolderTree> 过滤文件
        let splitResult = nodeData.name.split('.');
        let fileSuffix = splitResult.length > 1 ? splitResult.pop() : '';
        nodeData.suffix = fileSuffix;
        // 当前节点为文件，增加“重命名”“删除”等右键菜单
        nodeData.contextMenuData = [
            {
                name: "重命名",
                handler: (nodeRenderData) => {
                    // 将该节点转为 input 输入框
                    nodeRenderData.sourceData.input = true;
                    nodeRenderData.sourceData.completer = async (data, newName) => {
                        newName = newName.trim();
                        // 如果输入名称为空，不做任何变动，恢复当前节点
                        if (newName.length == 0) {
                            folderTreeRef.value.reRenderTreeNode(data);
                            return;
                        }
                        // 文件名不能包含 / 符号
                        if (newName.indexOf('/') >= 0) {
                            Message.error('不能包含 / 符号');
                            folderTreeRef.value.reRenderTreeNode(data);
                            return;
                        }
                        // 如果文件不以 .md 为后缀，同样恢复当前节点
                        if (!newName.endsWith('.md')) {
                            Message.error('只允许 .md 文件');
                            folderTreeRef.value.reRenderTreeNode(data);
                            return;
                        }
                        // 尝试重命名该节点
                        let newRenderNode = null;
                        let oldName = '';
                        let oldPath = nodeData.path;
                        let splitPathResult = oldPath.split('/');
                        try {
                            if (splitPathResult.length <= 1) {
                                // 恢复当前节点并报错
                                folderTreeRef.value.reRenderTreeNode(data);
                                throw new Error("该节点文件路径非法.");
                            }
                            oldName = splitPathResult.pop();
                            let newPath = splitPathResult.join('/') + '/' + newName;
                            // 检查新的路径是否已存在，避免覆盖其他文件
                            const exist = await exists(newPath);
                            if (exist) {
                                // 恢复当前节点并报错
                                folderTreeRef.value.reRenderTreeNode(data);
                                throw new Error("存在同名文件.");
                            }
                            data.sourceData.path = newPath;
                            data.sourceData.name = newName;
                            // 新的节点数据需要执行 appendDataForNode 操作
                            appendDataForNode(data.sourceData);
                            // 重新渲染当前节点
                            newRenderNode = folderTreeRef.value.reRenderTreeNode(data);
                            if (newRenderNode === false) {
                                throw new Error("变更文件树失败");
                            }
                            // 最后再尝试操作系统重命名
                            await rename(oldPath, newPath);
                            Message.success('重命名成功: ' + newPath);
                        } catch (err) {
                            Message.error('重命名失败: ' + err);
                            // 如果最后操作系统接口失败，需要回滚文件树新增的节点
                            if (newRenderNode !== null && newRenderNode !== false) {
                                newRenderNode.sourceData.path = oldPath;
                                newRenderNode.sourceData.name = oldName;
                                folderTreeRef.value.reRenderTreeNode(newRenderNode);
                            }
                        }
                    };
                    // 将当前节点重新渲染为输入框
                    folderTreeRef.value.reRenderTreeNode(nodeRenderData);
                }
            },
            {
                name: "删除",
                handler: async (nodeRenderData) => {
                    try {
                        if (folderTreeRef.value.removeTreeNode(nodeRenderData) === false) {
                            throw new Error("变更文件树失败");
                        }
                        await remove(nodeRenderData.path, { recursive: true });
                        Message.success('删除文件成功: ' + nodeRenderData.path);
                    } catch (err) {
                        Message.error('删除文件失败: ' + err);
                    }
                }
            },
        ];
    }
}

// <SelectFolder> 选择目录后赋值给 folderTreeData，然后再传递给 <FolderTree>
const folderTreeData = ref(null)
function showFileTree(treeData) {
    folderTreeData.value = treeData
}

const changeRootPath = (newRootPath) => {
    emit('update:rootFolderPath', newRootPath); // 触发双向绑定更新
}

const fileSelected = (fileRenderData) => {
    emit('update:currentFilePath', fileRenderData.path); // 触发双向绑定更新
}
</script>