package com.yingpaipay.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yingpaipay.business.constant.FolderTypeConst;
import com.yingpaipay.business.domain.Folder;
import com.yingpaipay.business.domain.Project;
import com.yingpaipay.business.domain.bo.FolderBo;
import com.yingpaipay.business.domain.bo.ProjectCenterListBo;
import com.yingpaipay.business.domain.bo.ProjectCenterMemberListBo;
import com.yingpaipay.business.domain.vo.FolderListVo;
import com.yingpaipay.business.domain.vo.FolderVo;
import com.yingpaipay.business.domain.vo.ProjectCenterListVo;
import com.yingpaipay.business.domain.vo.ProjectCenterMemberListVo;
import com.yingpaipay.system.domain.SysUserFolder;
import com.yingpaipay.system.mapper.SysUserFolderMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.BusinessException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.SysUser;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import com.yingpaipay.business.mapper.FolderMapper;
import com.yingpaipay.business.service.IFolderService;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Wrapper;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 文件夹管理Service业务层处理
 *
 * @author Huanyi
 * @date 2025-12-08
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class FolderServiceImpl implements IFolderService {

    private final FolderMapper baseMapper;
    private final SysUserFolderMapper userFolderMapper;

    private final ISysUserService userService;
    private final ISysDeptService deptService;

    @Override
    public List<FolderListVo> selectList(Long projectId) {
        List<Folder> folders = baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getProjectId, projectId));
        Map<Long, List<Folder>> childrenMap = folders.stream()
            .filter(this::isNotRoot)
            .collect(Collectors.groupingBy(Folder::getParentId));
        List<Folder> roots = folders.stream().filter(this::isRoot).toList();
        List<FolderListVo> vos = new ArrayList<>();
        roots.forEach(e -> {
            FolderListVo vo = new FolderListVo();
            vo.setId(e.getId());
            vo.setName(e.getName());
            vo.setType(e.getType());
            vo.setChildren(buildChildren(e, childrenMap));
            vos.add(vo);
        });
        return vos;
    }

    private List<FolderListVo> buildChildren(Folder folder, Map<Long, List<Folder>> childrenMap) {
        List<Folder> children = childrenMap.get(folder.getId());
        if (children == null || children.isEmpty()) {
            return Collections.emptyList();
        }

        return children.stream().map(childFolder -> {
            FolderListVo vo = new FolderListVo();
            vo.setId(childFolder.getId());
            vo.setName(childFolder.getName());
            vo.setType(childFolder.getType());
            vo.setChildren(buildChildren(childFolder, childrenMap));
            return vo;
        }).toList();
    }

    private boolean isRoot(Folder folder) {
        return folder.getParentId() == null;
    }

    private boolean isNotRoot(Folder folder) {
        return !isRoot(folder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertByBo(FolderBo bo) {
        Folder entity = MapstructUtils.convert(bo, Folder.class);
        boolean flag = baseMapper.insert(entity) == 0;
        if (flag) {
            throw new RuntimeException("插入失败");
        }
        checkInsertIsValid(bo);
        return true;
    }

    private void checkInsertIsValid(FolderBo bo) {
        if (bo.getParentId() == null) {
            return;
        }
        Folder parent = baseMapper.selectById(bo.getParentId());
        if (parent.getRestrictionLevel().equals(-1)) {
            return;
        }
        if (bo.getRestrictionLevel().equals(-1)) {
            throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
        }
        checkRestriction(parent.getId(), parent.getRestrictionLevel());
    }

    @Override
    public boolean deleteWithValidIds(Collection<Long> ids, Boolean isValid) {
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateByBo(FolderBo bo) {
        Folder entity = MapstructUtils.convert(bo, Folder.class);
        boolean flag = baseMapper.updateById(entity) == 0;
        if (flag) {
            throw new RuntimeException("更新操作失败");
        }
        checkInsertIsValid(bo);
        checkUpdateIsValid(bo);
        return true;
    }

    private void checkUpdateIsValid(FolderBo bo) {
        checkRestriction(bo.getId(), bo.getRestrictionLevel());
    }

    private void checkRestriction(Long parentId, Integer restrictionLevel) {
        if (restrictionLevel.equals(-1)) {
            return;
        }
        AtomicInteger total = new AtomicInteger();
        baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getParentId, parentId))
            .forEach(e -> {
                log.debug("当前层次文件夹名称 : {}; 限制个数 : {}", e.getName(), e.getRestrictionLevel());
                if (e.getRestrictionLevel().equals(-1)) {
                    throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
                }
                total.addAndGet(e.getRestrictionLevel());
            });
        if (total.get() > restrictionLevel) {
            throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
        }
    }

    @Override
    public FolderVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public TableDataInfo<ProjectCenterListVo> queryCenterInfo(ProjectCenterListBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Folder> wrapper = buildCenterQueryWrapper(bo);
        IPage<Folder> page = baseMapper.selectPage(pageQuery.build(), wrapper);
        List<Long> userIds = new ArrayList<>();
        Map<Long, String> userMap = new HashMap<>();
        page.getRecords().forEach(e -> {
            userIds.add(e.getCreateBy());
            userIds.add(e.getUpdateBy());
        });
        userService.selectUserByIds(userIds)
            .forEach(e -> userMap.put(e.getUserId(), e.getNickName()));
        return TableDataInfo.build(page.convert(e -> {
            ProjectCenterListVo vo = new ProjectCenterListVo();
            vo.setId(e.getId());
            vo.setName(e.getName());
            vo.setStatus(e.getStatus());
            vo.setCreateTime(e.getCreateTime());
            vo.setUpdateTime(e.getUpdateTime());
            vo.setCreateBy(userMap.get(e.getCreateBy()));
            vo.setUpdateBy(userMap.get(e.getUpdateBy()));
            return vo;
        }));
    }

    @Override
    public TableDataInfo<ProjectCenterMemberListVo> queryCenterMember(ProjectCenterMemberListBo bo, PageQuery pageQuery) {
        List<Long> folderIds = new ArrayList<>();
        Map<Long, String> folderMap = new HashMap<>();
        baseMapper.selectList(Wrappers.lambdaQuery(Folder.class)
                .like(StringUtils.isNotBlank(bo.getCenter()), Folder::getName, bo.getCenter())
                .eq(Folder::getProjectId, bo.getProjectId())
            ).forEach(e -> {
                folderIds.add(e.getId());
                folderMap.put(e.getId(), e.getName());
        });
        if (folderIds.isEmpty()) {
            return TableDataInfo.build();
        }
        List<SysUserFolder> userFolders = userFolderMapper.selectList(
            Wrappers.lambdaQuery(SysUserFolder.class).
                in(SysUserFolder::getFolderId, folderIds)
        );
        List<Long> userIds = new ArrayList<>();
        userFolders.forEach(e -> userIds.add(e.getUserId()));
        IPage<SysUser> page = userService.selectPageByNameAndIds(bo.getName(), userIds, pageQuery);
        List<Long> deptIds = new ArrayList<>();
        Map<Long, String> deptMap = new HashMap<>();
        page.getRecords().forEach(e -> deptIds.add(e.getDeptId()));
        if (!deptIds.isEmpty()) {
            deptService.selectDeptByIds(deptIds).forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
        }
        return TableDataInfo.build(page.convert(e -> {
            ProjectCenterMemberListVo vo = new ProjectCenterMemberListVo();
            StringBuilder centers = new StringBuilder();
            userFolders.stream()
                .filter(entity -> entity.getUserId().equals(e.getUserId()))
                .forEach(entity -> centers.append(folderMap.get(entity.getFolderId())).append(","));
            vo.setCenters(centers.toString());
            vo.setId(e.getUserId());
            vo.setName(e.getNickName());
            vo.setPhoneNumber(e.getPhonenumber());
            vo.setDept(deptMap.get(e.getDeptId()));
            vo.setTime(e.getCreateTime());
            return vo;
        }));
    }

    private LambdaQueryWrapper<Folder> buildCenterQueryWrapper(ProjectCenterListBo bo) {
        return Wrappers.lambdaQuery(Folder.class)
            .eq(Folder::getType, FolderTypeConst.CENTER)
            .eq(Folder::getProjectId, bo.getProjectId())
            .like(StringUtils.isNotBlank(bo.getName()), Folder::getName, bo.getName())
            .orderByDesc(Folder::getId);
    }

}
