package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
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.common.satoken.utils.LoginHelper;
import org.dromara.system.controller.constant.BusProjectConstant;
import org.dromara.system.domain.BusProject;
import org.dromara.system.domain.BusUserProjectRelevancy;
import org.dromara.system.domain.dto.project.BusProjectBatchByProjectListReq;
import org.dromara.system.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq;
import org.dromara.system.domain.dto.userprojectrelevancy.BusUserProjectRelevancyQueryReq;
import org.dromara.system.domain.dto.userprojectrelevancy.BusUserProjectRelevancyUpdateReq;
import org.dromara.system.domain.vo.userprojectrelevancy.BusLoginUserProjectRelevancyVo;
import org.dromara.system.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo;
import org.dromara.system.mapper.BusUserProjectRelevancyMapper;
import org.dromara.system.service.IBusProjectService;
import org.dromara.system.service.IBusUserProjectRelevancyService;
import org.dromara.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 系统用户与项目关联Service业务层处理
 *
 * @author lilemy
 * @date 2025-03-04
 */
@Service
public class BusUserProjectRelevancyServiceImpl extends ServiceImpl<BusUserProjectRelevancyMapper, BusUserProjectRelevancy>
    implements IBusUserProjectRelevancyService {

    @Resource
    private IBusProjectService projectService;

    @Lazy
    @Resource
    private ISysUserService userService;

    /**
     * 查询系统用户与项目关联
     *
     * @param id 主键
     * @return 系统用户与项目关联
     */
    @Override
    public BusUserProjectRelevancyVo queryById(Long id) {
        // 查询数据
        BusUserProjectRelevancy userProjectRelevancy = this.getById(id);
        if (userProjectRelevancy == null) {
            throw new ServiceException("对应用户与项目关联不存在", HttpStatus.NOT_FOUND);
        }
        // 封装并返回
        return this.getVo(userProjectRelevancy);
    }

    /**
     * 分页查询系统用户与项目关联列表
     *
     * @param req       查询条件
     * @param pageQuery 分页参数
     * @return 系统用户与项目关联分页列表
     */
    @Override
    public TableDataInfo<BusUserProjectRelevancyVo> queryPageList(BusUserProjectRelevancyQueryReq req, PageQuery pageQuery) {
        // 查询数据库
        Page<BusUserProjectRelevancy> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
        return TableDataInfo.build(this.getVoPage(result));
    }

    /**
     * 查询符合条件的系统用户与项目关联列表
     *
     * @param req 查询条件
     * @return 系统用户与项目关联列表
     */
    @Override
    public List<BusUserProjectRelevancyVo> queryList(BusUserProjectRelevancyQueryReq req) {
        LambdaQueryWrapper<BusUserProjectRelevancy> lqw = this.buildQueryWrapper(req);
        return this.list(lqw).stream().map(this::getVo).toList();
    }

    /**
     * 新增系统用户与项目关联
     *
     * @param req 系统用户与项目关联
     * @return 新增关联id
     */
    @Override
    public Long insertByBo(BusUserProjectRelevancyCreateReq req) {
        // 将实体类和 DTO 进行转换
        BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy();
        BeanUtils.copyProperties(req, userProjectRelevancy);
        // 数据校验
        validEntityBeforeSave(userProjectRelevancy, true);
        // 判断对应的用户与项目关联是否存在
        if (this.getOne(new LambdaQueryWrapper<BusUserProjectRelevancy>()
            .eq(BusUserProjectRelevancy::getUserId, userProjectRelevancy.getUserId())
            .eq(BusUserProjectRelevancy::getProjectId, userProjectRelevancy.getProjectId())) != null) {
            throw new ServiceException("用户和项目关联已存在", HttpStatus.CONFLICT);
        }
        // 写入数据库
        boolean save = this.save(userProjectRelevancy);
        if (!save) {
            throw new ServiceException("新增用户和项目关联失败，数据库异常", HttpStatus.ERROR);
        }
        // 返回新写入的数据 id
        return userProjectRelevancy.getId();
    }

    /**
     * 批量新增用户和项目关联
     *
     * @param projectId  项目ID
     * @param userIdList 用户ID列表
     * @param userType   用户类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatchByUserList(Long projectId, List<Long> userIdList, String userType) {
        if (ObjectUtils.isEmpty(projectId) || ObjectUtils.isEmpty(userIdList)) {
            return;
        }
        List<BusUserProjectRelevancy> userProjectRelevancyList = userIdList.stream().map(userId -> {
            BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy();
            userProjectRelevancy.setUserId(userId);
            userProjectRelevancy.setProjectId(projectId);
            userProjectRelevancy.setUserType(userType);
            return userProjectRelevancy;
        }).toList();
        boolean saveRelevancy = this.saveBatch(userProjectRelevancyList);
        if (!saveRelevancy) {
            throw new ServiceException("新增用户和项目关联失败，数据库异常", HttpStatus.ERROR);
        }
    }

    /**
     * 批量新增用户和项目关联
     *
     * @param projectIdList 项目ID列表
     * @param userId        用户ID
     * @param userType      用户类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatchByProjectList(List<Long> projectIdList, Long userId, String userType) {
        if (ObjectUtils.isEmpty(projectIdList) || ObjectUtils.isEmpty(userId) || StringUtils.isBlank(userType)) {
            return;
        }
        List<BusUserProjectRelevancy> userProjectRelevancyList = projectIdList.stream().map(projectId -> {
            BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy();
            userProjectRelevancy.setUserId(userId);
            userProjectRelevancy.setProjectId(projectId);
            userProjectRelevancy.setUserType(userType);
            return userProjectRelevancy;
        }).toList();
        boolean saveRelevancy = this.saveBatch(userProjectRelevancyList);
        if (!saveRelevancy) {
            throw new ServiceException("新增用户和项目关联失败，数据库异常", HttpStatus.ERROR);
        }
    }

    /**
     * 修改系统用户与项目关联
     *
     * @param req 系统用户与项目关联
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(BusUserProjectRelevancyUpdateReq req) {
        // 将实体类和 DTO 进行转换
        BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy();
        BeanUtils.copyProperties(req, userProjectRelevancy);
        // 数据校验
        validEntityBeforeSave(userProjectRelevancy, false);
        // 判断是否存在
        BusUserProjectRelevancy oldUserProjectRelevancy = this.getById(userProjectRelevancy.getId());
        if (oldUserProjectRelevancy == null) {
            throw new ServiceException("修改用户和项目关联失败，数据不存在", HttpStatus.NOT_FOUND);
        }
        // 操作数据库
        return this.updateById(oldUserProjectRelevancy);
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(BusUserProjectRelevancy entity, Boolean create) {
        // TODO 做一些数据校验,如唯一约束
        Long projectId = entity.getProjectId();
        Long userId = entity.getUserId();
        if (create) {
            if (projectId == null) {
                throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST);
            }
            if (userId == null) {
                throw new ServiceException("用户 id 不能为空", HttpStatus.BAD_REQUEST);
            }
        }
        // 判断对应项目是否存在
        if (projectService.getById(projectId) == null) {
            throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
        }
        // 判断对应用户是否存在
        if (userService.selectUserById(userId) == null) {
            throw new ServiceException("用户不存在", HttpStatus.NOT_FOUND);
        }
    }

    /**
     * 校验并批量删除系统用户与项目关联信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        // 获取当前登录用户
        Long userId = LoginHelper.getUserId();
        // 获取待删除数据详情
        List<BusUserProjectRelevancy> busUserProjectRelevancyList = this.listByIds(ids);
        if (isValid) {
            // 做一些业务上的校验,判断是否需要校验
            // 获取项目id列表
            List<Long> projectIdList = busUserProjectRelevancyList.stream().map(BusUserProjectRelevancy::getProjectId).toList();
            // 判断是否有权限操作对应项目下的内容
            projectService.validAuth(projectIdList, userId);
        }
        // 判断对应数据是否都存在
        if (busUserProjectRelevancyList.size() != ids.size()) {
            throw new ServiceException("删除系统用户与项目关联失败，数据缺失", HttpStatus.BAD_REQUEST);
        }
        return this.removeBatchByIds(ids);
    }

    /**
     * 根据用户ID删除系统用户与项目关联
     *
     * @param userId 用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByUserId(Long userId) {
        List<BusUserProjectRelevancy> relevancyList = this.lambdaQuery()
            .eq(BusUserProjectRelevancy::getUserId, userId)
            .list();
        if (CollUtil.isNotEmpty(relevancyList)) {
            boolean result = this.removeBatchByIds(relevancyList);
            if (!result) {
                throw new ServiceException("删除用户项目关联失败，数据库异常", HttpStatus.ERROR);
            }
        }
    }

    /**
     * 根据项目ID和用户ID列表删除系统用户与项目关联
     *
     * @param oldProjectId 项目ID
     * @param userIds      用户ID列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByProjectAndUserIds(Long oldProjectId, List<Long> userIds) {
        List<BusUserProjectRelevancy> relevancyList = this.lambdaQuery()
            .eq(BusUserProjectRelevancy::getProjectId, oldProjectId)
            .in(BusUserProjectRelevancy::getUserId, userIds)
            .list();
        if (CollUtil.isNotEmpty(relevancyList)) {
            boolean result = this.removeBatchByIds(relevancyList);
            if (!result) {
                throw new ServiceException("删除用户项目关联失败，数据库异常", HttpStatus.ERROR);
            }
        }
    }

    /**
     * 获取当前登录用户项目列表
     *
     * @param userId 登录用户ID
     * @return 当前登录用户项目列表
     */
    @Override
    public List<BusLoginUserProjectRelevancyVo> queryListByUserId(Long userId) {
        // 添加查询条件，根据当前用户，获取数据
        LambdaQueryWrapper<BusUserProjectRelevancy> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(BusUserProjectRelevancy::getUserId, userId);
        // 查询数据库，获取数据
        List<BusUserProjectRelevancy> list = this.list(queryWrapper);
        List<Long> projectIdList = list.stream().map(BusUserProjectRelevancy::getProjectId).toList();
        if (CollUtil.isEmpty(projectIdList)) {
            return new ArrayList<>();
        }
        Map<Long, List<BusProject>> projectMap = projectService.lambdaQuery()
            .select(BusProject::getId, BusProject::getParentId, BusProject::getProjectName, BusProject::getShortName)
            .in(BusProject::getId, projectIdList)
            .eq(BusProject::getParentId, BusProjectConstant.PARENT_ID)
            .list()
            .stream().collect(Collectors.groupingBy(BusProject::getId));
        // 获取封装
        return list.stream()
            .map(userProjectRelevancy -> {
                Long projectId = userProjectRelevancy.getProjectId();
                BusProject project = null;
                if (projectMap.containsKey(projectId)) {
                    project = projectMap.get(projectId).getFirst();
                }
                if (project != null && project.getParentId().equals(BusProjectConstant.PARENT_ID)) {
                    BusLoginUserProjectRelevancyVo loginUserProjectRelevancy = new BusLoginUserProjectRelevancyVo();
                    loginUserProjectRelevancy.setId(userProjectRelevancy.getId());
                    loginUserProjectRelevancy.setUserId(userProjectRelevancy.getUserId());
                    loginUserProjectRelevancy.setProjectId(projectId);
                    loginUserProjectRelevancy.setProjectName(project.getProjectName());
                    loginUserProjectRelevancy.setShortName(project.getShortName());
                    return loginUserProjectRelevancy;
                }
                return null;
            })
            .filter(Objects::nonNull)
            .toList();
    }

    /**
     * 获取当前登录用户项目分页
     *
     * @param userId    登录用户ID
     * @param req       分页查询条件
     * @param pageQuery 分页查询条件
     * @return 当前登录用户项目分页
     */
    @Override
    public TableDataInfo<BusUserProjectRelevancyVo> queryPageByUserId(Long userId, BusUserProjectRelevancyQueryReq req,
                                                                      PageQuery pageQuery) {
        // 添加查询条件
        req.setUserId(userId);
        LambdaQueryWrapper<BusUserProjectRelevancy> queryWrapper = this.buildQueryWrapper(req);
        // 查询数据库
        Page<BusUserProjectRelevancy> result = this.page(pageQuery.build(), queryWrapper);
        return TableDataInfo.build(this.getVoPage(result));
    }

    /**
     * 批量新增用户和项目关联
     *
     * @param req 新增参数
     * @return 是否增加成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertBatchByProjectList(BusProjectBatchByProjectListReq req) {
        Long userId = req.getUserId();
        List<Long> projectIdList = req.getProjectIdList();
        long count = projectService.count(new QueryWrapper<BusProject>().in("id", projectIdList));
        if (count < projectIdList.size()) {
            throw new ServiceException("项目ID列表错误，一个或多个项目不存在", HttpStatus.NOT_FOUND);
        }
        List<BusUserProjectRelevancy> userProjectRelevancyList = projectIdList.stream().map(projectId -> {
            BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy();
            userProjectRelevancy.setUserId(userId);
            userProjectRelevancy.setProjectId(projectId);
            // 查询对应用户与项目关联信息是否存在
            QueryWrapper<BusUserProjectRelevancy> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId);
            queryWrapper.eq("project_id", projectId);
            // 如果存在则不保存
            BusUserProjectRelevancy one = this.getOne(queryWrapper);
            if (one != null) {
                return null;
            }
            return userProjectRelevancy;
        }).filter(Objects::nonNull).toList();
        if (userProjectRelevancyList.isEmpty()) {
            throw new ServiceException("对应用户与项目关系均已存在，无需重复添加", HttpStatus.BAD_REQUEST);
        }
        // 当用户与项目关系存在时修改，不存在则保存
        return this.saveOrUpdateBatch(userProjectRelevancyList);
    }

    /**
     * 获取系统用户与项目关联视图
     *
     * @param userProjectRelevancy 系统用户与项目关联
     * @return 系统用户与项目关联视图
     */
    @Override
    public BusUserProjectRelevancyVo getVo(BusUserProjectRelevancy userProjectRelevancy) {
        // 对象转封装类
        BusUserProjectRelevancyVo userProjectRelevancyVo = new BusUserProjectRelevancyVo();
        if (userProjectRelevancy == null) {
            return userProjectRelevancyVo;
        }
        BeanUtils.copyProperties(userProjectRelevancy, userProjectRelevancyVo);
        // 关联查询项目信息
        Long projectId = userProjectRelevancy.getProjectId();
        if (projectId != null) {
            userProjectRelevancyVo.setProject(projectService.queryById(projectId));
        }
        return userProjectRelevancyVo;
    }

    /**
     * 获取用户和项目关联对象查询条件封装
     *
     * @param req 查询条件
     * @return 查询条件封装
     */
    @Override
    public LambdaQueryWrapper<BusUserProjectRelevancy> buildQueryWrapper(BusUserProjectRelevancyQueryReq req) {
        LambdaQueryWrapper<BusUserProjectRelevancy> queryWrapper = new LambdaQueryWrapper<>();
        if (req == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long userId = req.getUserId();
        Long projectId = req.getProjectId();
        String userType = req.getUserType();
        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), BusUserProjectRelevancy::getUserId, userId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(projectId), BusUserProjectRelevancy::getProjectId, projectId);
        queryWrapper.eq(StringUtils.isNotBlank(userType), BusUserProjectRelevancy::getUserType, userType);
        return queryWrapper;
    }

    /**
     * 获取系统用户与项目关联分页视图
     *
     * @param userProjectRelevancyPage 系统用户与项目关联分页
     * @return 系统用户与项目关联分页视图
     */
    @Override
    public Page<BusUserProjectRelevancyVo> getVoPage(Page<BusUserProjectRelevancy> userProjectRelevancyPage) {
        List<BusUserProjectRelevancy> userProjectRelevancyList = userProjectRelevancyPage.getRecords();
        Page<BusUserProjectRelevancyVo> userProjectRelevancyVoPage = new Page<>(
            userProjectRelevancyPage.getCurrent(),
            userProjectRelevancyPage.getSize(),
            userProjectRelevancyPage.getTotal());
        if (CollUtil.isEmpty(userProjectRelevancyList)) {
            return userProjectRelevancyVoPage;
        }
        // 对象列表 => 封装对象列表
        List<BusUserProjectRelevancyVo> userProjectRelevancyVoList = userProjectRelevancyList.stream().map(this::getVo).toList();
        userProjectRelevancyVoPage.setRecords(userProjectRelevancyVoList);
        return userProjectRelevancyVoPage;
    }

}
