<!--
简述：支持选择目录，遍历返回文件树。
注意：配置好 fs:scope 的权限范围，否则会报错 forbidden path
文件树示例：
{
    "path": "root-path/root",
    "name": "root",
    "directory": true,
    "nodes": [
        {
            "path": "root-path/root/folder1",
            "name": "folder1",
            "directory": true,
            "nodes": [
                {
                    "path": "root-path/root/folder1/folder1-file2",
                    "name": "folder1-file2.txt.md",
                    "directory": false,
                },
            ]
        },
        {
            "path": "root-path/root/file3",
            "name": "file3.txt",
            "directory": false,
        },
    ]
}
-->
<template>
    <Button type="primary" @click="selectFolder">选择目录</Button>
</template>

<script>
import { join } from '@tauri-apps/api/path';
import { open } from '@tauri-apps/plugin-dialog';
import { readDir } from '@tauri-apps/plugin-fs';

export default {
    props: {
        rootPath: {
            type: String,
            required: false,
            default: ''
        },
        // 生成 node 数据时，支持执行自定义操作
        nodeDataCallback: {
            type: Function,
            required: false,
            default: (node) => {
                // 操作 node 数据，可以增加自定义字段
                return;
            }
        },
    },
    mounted() {
        // 如果父组件已指定了初始目录，则遍历返回对应文件树
        this.exposeTreeData(this.rootPath)
    },
    methods: {
        async exposeTreeData(folderPath) {
            if (folderPath != null && folderPath.length > 0) {
                const folderTreeData = await this.readDirRecursively(folderPath);
                this.$emit('folder-selected', folderTreeData);
            }
        },
        async selectFolder() {
            if (window.__TAURI_INTERNALS__ === undefined) {
                // TODO 请求后端接口，选择目录
                // 告诉父组件，rootPath 的值已变化
                this.$emit('update:rootPath', '/root')
                await this.exposeTreeData('/root')
                return;
            }
            const folderPath = await open(
                {
                    filters: [{ name: 'All Files', extensions: ['.'] }],
                    directory: true
                }
            );
            if (folderPath) {
                // 告诉父组件，rootPath 的值已变化
                this.$emit('update:rootPath', folderPath)
                await this.exposeTreeData(folderPath)
            }
        },
        // 遍历文件夹，返回文件树
        async readDirRecursively(folderPath) {
            if (window.__TAURI_INTERNALS__ === undefined) {
                // TODO 请求后端接口，获取目录树
                const folderTreeData = {
                    "path": folderPath,
                    "name": folderPath.split('/').pop(),
                    "nodes": [{
                        "path": '/root/test.md',
                        "name": 'test.md',
                        "suffix": "md",
                        "directory": false,
                    },{
                        "path": '/root/test1.md',
                        "name": 'test1.md',
                        "suffix": "md",
                        "directory": false,
                    }],
                    "directory": true,
                }
                return folderTreeData;
            }
            // 拼接得到当前文件夹路径
            let folderTreeNode = {
                "path": folderPath,
                "name": folderPath.split('/').pop(),
                "nodes": [],
                "directory": true,
            }
            this.nodeDataCallback(folderTreeNode);

            // 尝试读取 folderPath 目录下所有实体
            let entries;
            try {
                entries = await readDir(folderPath);
            } catch (err) {
                let errorMessage = ""
                if (err.startsWith("forbidden path")) {
                    errorMessage = "no permission. " + err
                } else {
                    errorMessage = "readDir failed. " + err
                }
                this.$Message.error({
                    content: errorMessage,
                    duration: 10,
                    closable: true
                });
                return folderTreeNode
            }
            // 遍历该文件夹下所有实体
            for (const entry of entries) {
                const entryPath = await join(folderPath, entry.name);
                if (entry.isDirectory) {
                    folderTreeNode.nodes.push(await this.readDirRecursively(entryPath))
                } else {
                    let subTreeNode = {
                        "path": entryPath,
                        "name": entry.name,
                        "directory": false,
                    }
                    this.nodeDataCallback(subTreeNode)
                    folderTreeNode.nodes.push(subTreeNode)
                }
            }
            return folderTreeNode
        }
    }
}
</script>