package com.yingpaipay.business.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yingpaipay.business.constant.DocumentTypeConst;
import com.yingpaipay.business.constant.FolderTypeConst;
import com.yingpaipay.business.constant.SpecificationTypeConst;
import com.yingpaipay.business.domain.Folder;
import com.yingpaipay.business.mapper.FolderMapper;
import com.yingpaipay.system.domain.SysUserFolders;
import com.yingpaipay.system.mapper.SysUserFoldersMapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;

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

@Service
@RequiredArgsConstructor
public class CommonFolderService {

    private final FolderMapper baseMapper;
    private final SysUserFoldersMapper userFoldersMapper;

    public List<Long> selectIds(String centerName, List<Long> projectIds) {
        if (projectIds.isEmpty()) {
            return List.of();
        }
        List<Long> ids = new ArrayList<>();
        List<Long> centerIds = new ArrayList<>();
        List<Folder> allFolders = baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).in(Folder::getProjectId, projectIds));
        Map<Long, List<Folder>> childrenMap = allFolders
            .stream()
            .filter(e -> e.getParentId() != null)
            .collect(Collectors.groupingBy(Folder::getParentId));
        Map<Long, List<Folder>> folderProjectMap = allFolders.stream().filter(e -> e.getParentId() == null).collect(Collectors.groupingBy(Folder::getProjectId));
        userFoldersMapper.selectList(
            Wrappers.lambdaQuery(SysUserFolders.class)
                .eq(SysUserFolders::getUserId, LoginHelper.getUserId())
                .in(SysUserFolders::getProjectId, projectIds)
        ).forEach(e -> {
            if (e.getFolders().equals("*")) {
                List<Folder> folders = folderProjectMap.get(e.getProjectId());
                for (Folder folder : folders) {
                    centerIds.add(folder.getId());
                }
            } else if (!e.getFolders().isEmpty()) {
                centerIds.addAll(Arrays.stream(e.getFolders().split(",")).map(Long::valueOf).toList());
            }
        });

        for (Long centerId : centerIds) {
            buildAuthrizedFolders(centerId, ids, childrenMap);
        }

        return ids;
    }

    private void buildAuthrizedFolders(Long centerId, List<Long> ids, Map<Long, List<Folder>> childrenMap) {
        ids.add(centerId);
        List<Folder> folders = childrenMap.get(centerId);
        if (folders == null || folders.isEmpty()) {
            return;
        }
        for (Folder folder : folders) {
            buildAuthrizedFolders(folder.getId(), ids, childrenMap);
        }
    }

    public int getSpecificationType(Long folderId, Long projectId) {
        Map<Long, Folder> folderMap = new HashMap<>();
        baseMapper.selectList(
            Wrappers.lambdaQuery(Folder.class)
                .eq(Folder::getProjectId, projectId)
        ).forEach(e -> folderMap.put(e.getId(), e));

        long currentId = folderId;

        while (true) {
            Folder folder = folderMap.get(currentId);
            if (folder == null || folder.getType().equals(FolderTypeConst.COUNTRY)) {
                return SpecificationTypeConst.PROJECT;
            }
            if (folder.getType().equals(FolderTypeConst.CENTER)) {
                return SpecificationTypeConst.CENTER;
            }
            if (folder.getType().equals(FolderTypeConst.NORMAL)) {
                if (folder.getParentId() == null) {
                    return SpecificationTypeConst.PROJECT;
                }
                currentId = folder.getParentId();
            }
        }
    }

    public List<Folder> queryListByIds(List<Long> folderIds) {
        if (folderIds.isEmpty()) {
            return List.of();
        }
        return baseMapper.selectByIds(folderIds);
    }

    public Folder getById(Long folderId) {
        return baseMapper.selectById(folderId);
    }

    public List<Long> selectIdsOnFiling(String centerName, List<Long> projectIds) {
        if (projectIds.isEmpty()) {
            return List.of();
        }
        List<Long> ids = new ArrayList<>();
        List<Long> centerIds = new ArrayList<>();
        List<Folder> allFolders = baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).in(Folder::getProjectId, projectIds));
        Map<Long, List<Folder>> childrenMap = allFolders
            .stream()
            .filter(e -> e.getParentId() != null)
            .collect(Collectors.groupingBy(Folder::getParentId));
        Map<Long, List<Folder>> folderProjectMap = allFolders.stream().filter(e -> e.getParentId() == null).collect(Collectors.groupingBy(Folder::getProjectId));
        userFoldersMapper.selectList(
            Wrappers.lambdaQuery(SysUserFolders.class)
                .eq(SysUserFolders::getUserId, LoginHelper.getUserId())
                .in(SysUserFolders::getProjectId, projectIds)
        ).forEach(e -> {
            // 有可能将权限全部收回
            if (e.getFolders().isEmpty()) {
            } else if (e.getFolders().equals("*")) {
                List<Folder> folders = folderProjectMap.get(e.getProjectId());
                for (Folder folder : folders) {
                    centerIds.add(folder.getId());
                }
            } else {
                centerIds.addAll(Arrays.stream(e.getFolders().split(",")).map(Long::valueOf).toList());
            }
        });

        for (Long centerId : centerIds) {
            buildAuthrizedFolders(centerId, ids, childrenMap);
        }

        return ids;
    }

    public List<Folder> listByIds(List<Long> ids) {
        if (ids.isEmpty()) {
            return List.of();
        }
        return baseMapper.selectByIds(ids);
    }

    public List<Folder> queryByProjectIds(List<Long> projectIds) {
        if (projectIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<Folder> folders = baseMapper.selectList(
            Wrappers.lambdaQuery(Folder.class)
                .in(Folder::getProjectId, projectIds)
        );
        Map<Long, String> userFolderMap = new HashMap<>();
        userFoldersMapper.selectList(
            Wrappers.lambdaQuery(SysUserFolders.class)
                .eq(SysUserFolders::getUserId, LoginHelper.getUserId())
                .in(SysUserFolders::getProjectId, projectIds)
        ).forEach(e -> userFolderMap.put(e.getProjectId(), e.getFolders()));

        Map<Long, List<Folder>> folderProjectMap = folders.stream().collect(Collectors.groupingBy(Folder::getProjectId));

        return buildFinalFolders(folderProjectMap, userFolderMap);
    }

    private List<Folder> buildFinalFolders(Map<Long, List<Folder>> folderProjectMap, Map<Long, String> userFolderMap) {
        List<Folder> folders = new ArrayList<>();

        folderProjectMap.forEach((projectId, folderList) -> {
            String permission = userFolderMap.get(projectId);
            if (StringUtils.isBlank(permission)) {
                return;
            }
            if (permission.equals("*")) {
                folders.addAll(folderList);
            } else {
                Map<Long, List<Folder>> childrenMap = folderList.stream().filter(e -> e.getParentId() != null).collect(Collectors.groupingBy(Folder::getParentId));
                Map<Long, Folder> folderMap = new HashMap<>();
                folderList.forEach(e -> folderMap.put(e.getId(), e));
                List<Long> folderIds = Arrays.stream(permission.split(",")).map(Long::valueOf).toList();
                for (Long folderId : folderIds) {
                    buildFolders(folderMap.get(folderId), folders, childrenMap);
                }
            }
        });

        return folders;
    }

    private void buildFolders(Folder folder, List<Folder> folders, Map<Long, List<Folder>> childrenMap) {
        folders.add(folder);
        List<Folder> children = childrenMap.get(folder.getId());
        if (children == null || children.isEmpty()) {
            return;
        }
        children.forEach(e -> buildFolders(e, folders, childrenMap));
    }

    public List<Folder> queryByProjectId(Long projectId) {
        return baseMapper.selectList(
            Wrappers.lambdaQuery(Folder.class)
                .eq(Folder::getProjectId, projectId)
        );
    }

    public String getPathById(Long folderId, Long projectId) {
        Map<Long, Folder> map = new HashMap<>();
        queryByProjectId(projectId).forEach(e -> map.put(e.getId(), e));
        StringBuilder sb = new StringBuilder();
        Folder currentFolder = map.get(folderId);

        while (currentFolder != null) {
            sb.insert(0, currentFolder.getName()).insert(0, "/");
            if (currentFolder.getParentId() == null) {
                break;
            }
            currentFolder = map.get(currentFolder.getParentId());
        }
        return sb.toString();
    }
}
