package cn.reghao.tnb.file.app.zdisk.service;

import cn.reghao.jutil.jdk.web.db.Page;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.oss.api.constant.ObjectType;
import cn.reghao.tnb.common.auth.UserContext;
import cn.reghao.tnb.file.app.zdisk.db.mapper.DiskFileMapper;
import cn.reghao.tnb.file.app.zdisk.model.dto.CreateFolder;
import cn.reghao.tnb.file.app.zdisk.model.po.DiskFile;
import cn.reghao.tnb.file.app.zdisk.model.query.DiskQuery;
import cn.reghao.tnb.file.app.zdisk.model.vo.FolderTree;
import cn.reghao.tnb.file.app.zdisk.util.FileUtil;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2025-09-01 11:28:03
 */
@Service
public class DiskFolderService {
    private final DiskFileService diskFileService;
    private final DiskFileMapper diskFileMapper;

    public DiskFolderService(DiskFileService diskFileService, DiskFileMapper diskFileMapper) {
        this.diskFileService = diskFileService;
        this.diskFileMapper = diskFileMapper;
    }

    public synchronized Result createFolder(CreateFolder createFolder) {
        String pid = createFolder.getPid();
        DiskFile parentDiskFile = diskFileService.findByFileId(pid);
        if (parentDiskFile == null) {
            return Result.fail("parent dir not exist");
        }

        String parentPath = parentDiskFile.getPath();
        String folderName = createFolder.getFolderName();
        String folderPath = String.format("%s/%s", parentPath, folderName);
        String folderPath0 = FileUtil.getCanonicalPath(folderPath);
        DiskFile diskFile = diskFileService.findByPath(folderPath0);
        if (diskFile != null) {
            return Result.fail("current dir exist");
        }

        DiskFile folder = new DiskFile(FileUtil.getFileId(), pid, folderPath0, folderName);
        diskFileMapper.save(folder);
        return Result.success();
    }

    public synchronized String createFolders(String folderPath, long owner) {
        File file = new File(folderPath);
        String dirPath = file.getAbsolutePath();

        String pid = "0";
        if (dirPath.equals("/")) {
            return pid;
        }

        DiskQuery diskQuery = new DiskQuery.Builder()
                .path(dirPath)
                .owner(owner)
                .build();
        Page page = new Page(1, 1);
        List<DiskFile> diskFileList = diskFileMapper.findDiskQueryByPage(page, diskQuery);
        if (!diskFileList.isEmpty()) {
            return diskFileList.get(0).getFileId();
        }

        String savedDirPath = dirPath;
        List<String> list = new ArrayList<>();
        list.add(dirPath);

        int idx = dirPath.lastIndexOf("/");
        while (idx != 0) {
            dirPath = dirPath.substring(0, idx);
            list.add(dirPath);
            idx = dirPath.lastIndexOf("/");
        }
        Collections.reverse(list);

        for (String parent : list) {
            diskQuery.setPath(parent);
            diskFileList = diskFileMapper.findDiskQueryByPage(page, diskQuery);
            if (!diskFileList.isEmpty()) {
                pid = diskFileList.get(0).getFileId();
            } else {
                String fileId = FileUtil.getFileId();
                String path = FileUtil.getCanonicalPath(parent);
                String dirname = parent.substring(parent.lastIndexOf("/")+1);
                diskFileMapper.save(new DiskFile(fileId, pid, path, dirname));
                pid = fileId;
            }
        }

        diskQuery.setPath(savedDirPath);
        diskFileList = diskFileMapper.findDiskQueryByPage(page, diskQuery);
        return diskFileList.get(0).getFileId();
    }

    /**
     * elementui 的 el-tree
     *
     * @param
     * @return
     * @date 2025-09-05 16:29:33
     */
    public List<FolderTree> getFolderTree() {
        DiskFile root = diskFileMapper.findRoot();
        if (root == null) {
            return Collections.emptyList();
        }

        long loginUser = UserContext.getUserId();
        DiskQuery diskQuery = new DiskQuery.Builder()
                .fileType(ObjectType.Dir.getCode())
                .owner(loginUser)
                .build();

        Page page = new Page(1, 1000);
        List<DiskFile> diskFileList = diskFileMapper.findDiskQueryByPage(page, diskQuery);
        List<FolderTree> topChildren = getCollapsedTree(diskFileList);

        FolderTree treeRoot = new FolderTree(root);
        treeRoot.setChildren(topChildren);
        return List.of(treeRoot);
    }

    /**
     * 获取一棵收拢的树
     *
     * @param
     * @return
     * @date 2025-09-05 16:27:03
     */
    private List<FolderTree> getCollapsedTree(List<DiskFile> folderList) {
        Map<String, FolderTree> map = folderList.stream()
                .map(FolderTree::new)
                .collect(Collectors.groupingBy(FolderTree::getLabel,
                        Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));

        // 按 path 长度降序
        List<String> list = map.keySet().stream()
                .sorted((o1, o2) -> o2.length()-o1.length())
                .collect(Collectors.toList());

        // 对于一棵树, 从最下面的节点往上收拢
        for (String path : list) {
            int idx = path.lastIndexOf("/");
            String parentPath = path.substring(0, idx);
            if (parentPath.isBlank()) {
                continue;
            }

            FolderTree folderTree = map.get(path);
            map.get(parentPath).getChildren().add(folderTree);
            map.remove(path);
        }
        return new ArrayList<>(map.values());
    }
}
