package org.dromara.project.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
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.CommonConstant;
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.sql.SqlUtil;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.domain.req.project.ProjectBatchByProjectListReq;
import org.dromara.project.domain.req.userprojectrelevancy.UserProjectRelevancyCreateReq;
import org.dromara.project.domain.req.userprojectrelevancy.UserProjectRelevancyQueryReq;
import org.dromara.project.domain.req.userprojectrelevancy.UserProjectRelevancyUpdateReq;
import org.dromara.project.domain.resp.userprojectrelevancy.LoginUserProjectRelevancyResp;
import org.dromara.project.domain.vo.BusUserProjectRelevancyVo;
import org.dromara.project.mapper.BusUserProjectRelevancyMapper;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusUserProjectRelevancyService;
import org.dromara.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

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

    @Resource
    private BusUserProjectRelevancyMapper baseMapper;

    @Resource
    private IBusProjectService projectService;

    @Resource
    private ISysUserService userService;

    /**
     * 查询系统用户与项目关联
     *
     * @param id 主键
     * @return 系统用户与项目关联
     */
    @Override
    public BusUserProjectRelevancyVo queryById(Long id) {
        // 查询数据
        BusUserProjectRelevancy userProjectRelevancy = this.getById(id);
        // 封装并返回
        return this.getVo(userProjectRelevancy);
    }

    /**
     * 分页查询系统用户与项目关联列表
     *
     * @param req 查询条件
     * @return 系统用户与项目关联分页列表
     */
    @Override
    public Page<BusUserProjectRelevancyVo> queryPageList(UserProjectRelevancyQueryReq req) {
        long current = req.getCurrent();
        long size = req.getPageSize();
        QueryWrapper<BusUserProjectRelevancy> queryWrapper = this.getQueryWrapper(req);
        // 查询数据库
        Page<BusUserProjectRelevancy> result = this.page(new Page<>(current, size), this.getQueryWrapper(req));
        return this.getVoPage(result);
    }

    /**
     * 查询符合条件的系统用户与项目关联列表
     *
     * @param req 查询条件
     * @return 系统用户与项目关联列表
     */
    @Override
    public List<BusUserProjectRelevancyVo> queryList(UserProjectRelevancyQueryReq req) {
        QueryWrapper<BusUserProjectRelevancy> queryWrapper = this.getQueryWrapper(req);
        return baseMapper.selectVoList(queryWrapper);
    }

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

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(BusUserProjectRelevancy entity) {
        // TODO 做一些数据校验,如唯一约束
        Long projectId = entity.getProjectId();
        Long userId = entity.getUserId();
        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
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 获取当前登录用户项目列表
     *
     * @param userId 登录用户ID
     * @return 当前登录用户项目列表
     */
    @Override
    public List<LoginUserProjectRelevancyResp> queryListByUserId(Long userId) {
        // 添加查询条件，根据当前用户，获取数据
        LambdaQueryWrapper<BusUserProjectRelevancy> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(BusUserProjectRelevancy::getUserId, userId);
        // 查询数据库，获取数据
        List<BusUserProjectRelevancy> list = this.list(queryWrapper);
        // 获取封装
        return list.stream()
            .map(userProjectRelevancy -> {
                Long projectId = userProjectRelevancy.getProjectId();
                QueryWrapper<BusProject> projectQueryWrapper = new QueryWrapper<>();
                projectQueryWrapper.eq("id", projectId);
                BusProject project = projectService.getOne(projectQueryWrapper);
                if (project != null) {
                    LoginUserProjectRelevancyResp loginUserProjectRelevancy = new LoginUserProjectRelevancyResp();
                    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    分页查询条件
     * @return 当前登录用户项目分页
     */
    @Override
    public Page<BusUserProjectRelevancyVo> queryPageByUserId(Long userId, UserProjectRelevancyQueryReq req) {
        long current = req.getCurrent();
        long size = req.getPageSize();
        // 添加查询条件
        req.setUserId(userId);
        QueryWrapper<BusUserProjectRelevancy> queryWrapper = this.getQueryWrapper(req);
        // 查询数据库
        Page<BusUserProjectRelevancy> result = this.page(new Page<>(current, size), queryWrapper);
        return this.getVoPage(result);
    }

    /**
     * 批量新增用户和项目关联
     *
     * @param req 新增参数
     * @return 是否增加成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertBatchByProjectList(ProjectBatchByProjectListReq req) {
        Long userId = req.getUserId();
        Long[] projectIdList = req.getProjectIdList();
        long count = projectService.count(new QueryWrapper<BusProject>().in("id", (Object[]) projectIdList));
        if (count < projectIdList.length) {
            throw new ServiceException("项目ID列表错误，一个或多个项目不存在", HttpStatus.NOT_FOUND);
        }
        List<BusUserProjectRelevancy> userProjectRelevancyList = Arrays.stream(projectIdList).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 QueryWrapper<BusUserProjectRelevancy> getQueryWrapper(UserProjectRelevancyQueryReq req) {
        QueryWrapper<BusUserProjectRelevancy> queryWrapper = new QueryWrapper<>();
        if (req == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = req.getId();
        Long userId = req.getUserId();
        Long projectId = req.getProjectId();
        String sortField = req.getSortField();
        String sortOrder = req.getSortOrder();
        String underlineSortField = StrUtil.toUnderlineCase(sortField);
        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(projectId), "project_id", projectId);
        // 排序规则
        queryWrapper.orderBy(SqlUtil.validSortField(sortField),
            sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
            underlineSortField);
        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;
    }

}
