package org.dromara.personnel.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.personnel.domain.bo.OpsSchedulingReq;
import org.dromara.personnel.domain.bo.SchedulingUserTypeBo;
import org.dromara.personnel.domain.dto.SchedulingUserGroupDTO;
import org.dromara.personnel.domain.dto.UserTypePairDTO;
import org.dromara.personnel.domain.vo.OpsSchedulingDateVo;
import org.dromara.personnel.service.IOpsSchedulingDateService;
import org.dromara.system.api.RemoteUserService;
import org.springframework.stereotype.Service;
import org.dromara.personnel.domain.bo.OpsSchedulingBo;
import org.dromara.personnel.domain.vo.OpsSchedulingVo;
import org.dromara.personnel.domain.OpsScheduling;
import org.dromara.personnel.mapper.OpsSchedulingMapper;
import org.dromara.personnel.service.IOpsSchedulingService;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 运维-人员排班Service业务层处理
 *
 * @author LionLi
 * @date 2025-09-19
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OpsSchedulingServiceImpl extends ServiceImpl<OpsSchedulingMapper,OpsScheduling> implements IOpsSchedulingService {

    private final OpsSchedulingMapper baseMapper;
    private final IOpsSchedulingDateService  schedulingDateService;
    private final RemoteUserService remoteUserService;

    /**
     * 查询运维-人员排班
     *
     * @param id 主键
     * @return 运维-人员排班
     */
    @Override
    public OpsSchedulingVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询运维-人员排班列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 运维-人员排班分页列表
     */
    @Override
    public TableDataInfo<OpsSchedulingVo> queryPageList(OpsSchedulingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OpsScheduling> lqw = buildQueryWrapper(bo);
        Page<OpsSchedulingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的运维-人员排班列表
     *
     * @param bo 查询条件
     * @return 运维-人员排班列表
     */
    @Override
    public List<OpsSchedulingVo> queryList(OpsSchedulingBo bo) {
        LambdaQueryWrapper<OpsScheduling> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OpsScheduling> buildQueryWrapper(OpsSchedulingBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OpsScheduling> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(OpsScheduling::getId);
        lqw.eq(bo.getOpsUserId() != null, OpsScheduling::getOpsUserId, bo.getOpsUserId());
        lqw.eq(bo.getSchedulingType() != null, OpsScheduling::getSchedulingType, bo.getSchedulingType());
        lqw.eq(bo.getSchedulingDate() != null, OpsScheduling::getSchedulingDate, bo.getSchedulingDate());
        lqw.eq(bo.getSchedulingStartTime() != null, OpsScheduling::getSchedulingStartTime, bo.getSchedulingStartTime());
        lqw.eq(bo.getSchedulingEndTime() != null, OpsScheduling::getSchedulingEndTime, bo.getSchedulingEndTime());
        return lqw;
    }

    /**
     * 新增运维-人员排班
     *
     * @param bo 运维-人员排班
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(OpsSchedulingBo bo) {
        List<OpsScheduling> opsSchedulings = new ArrayList<>();
        for (SchedulingUserTypeBo userTypeBo : bo.getUserTypeBos()) {
            OpsSchedulingDateVo opsSchedulingDateVo = schedulingDateService.queryById(userTypeBo.getSchedulingType());
            if (opsSchedulingDateVo == null) {
                throw new ServiceException("排班类型不存在");
            }
            for (Long userId : userTypeBo.getOpsUserId()) {
                OpsScheduling opsScheduling = new OpsScheduling();
                if (userTypeBo.getOpsUserId() == null) {
                    throw new ServiceException("运维人员不能为空");
                }
                if (userTypeBo.getSchedulingType() == null) {
                    throw new ServiceException("排班类型不能为空");
                }
                if (bo.getSchedulingDate().isBefore(LocalDate.now())){
                    throw new ServiceException("排班日期应大于等于当前日期");
                }
                opsScheduling.setOpsUserId(userId);
                opsScheduling.setSchedulingType(userTypeBo.getSchedulingType());
                opsScheduling.setSchedulingDate(bo.getSchedulingDate());
                opsScheduling.setProjectId(bo.getProjectId());
                opsScheduling.setSchedulingStartTime(bo.getSchedulingDate().atTime(opsSchedulingDateVo.getStartTime()));
                opsScheduling.setSchedulingEndTime(bo.getSchedulingDate().atTime(opsSchedulingDateVo.getEndTime()));
                opsSchedulings.add(opsScheduling);
            }
        }
        return baseMapper.insertBatch(opsSchedulings);
    }

    /**
     * 修改运维-人员排班
     *
     * @param bo 运维-人员排班
     * @return 是否修改成功
     */
    @Override
    public Boolean allEdit(OpsSchedulingBo bo) {
        baseMapper.delete(new LambdaQueryWrapper<OpsScheduling>()
            .eq(OpsScheduling::getSchedulingDate,bo.getSchedulingDate())
            .eq(OpsScheduling::getProjectId,bo.getProjectId()));
        return insertByBo(bo);
    }

    @Override
    public Boolean insertOneByBo(OpsSchedulingBo bo) {
        OpsScheduling add = MapstructUtils.convert(bo, OpsScheduling.class);
        validEntityBeforeSave(add);
        boolean falt = baseMapper.insert(add) > 0;
        if (falt) {
            bo.setId(add.getId());
        }
        return falt;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(OpsSchedulingBo bo) {
        OpsScheduling update = MapstructUtils.convert(bo, OpsScheduling.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(OpsScheduling entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除运维-人员排班信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 根据项目和日期范围获取所有排班信息
     * @param req
     * @return
     */
    @Override
    public List<SchedulingUserGroupDTO> getRiLiList(OpsSchedulingReq req) {
        //根据项目和日期范围获取所有排班信息并根据日期正序排序
        List<OpsSchedulingVo> opsSchedulings = baseMapper.getRiLiList(req);
        List<SchedulingUserGroupDTO> schedulingDateGroupDTOS = new ArrayList<>();
        //过滤掉空白日期，并根据日期分组
        Map<Long, List<OpsSchedulingVo>> map = opsSchedulings.stream()
            .filter(opsScheduling -> opsScheduling.getSchedulingDate() != null)
            .collect(Collectors.groupingBy(
                OpsSchedulingVo::getOpsUserId,
                Collectors.toList()));
        //将分组内容拼装成对象
        for (Map.Entry<Long, List<OpsSchedulingVo>> entry : map.entrySet()) {
            SchedulingUserGroupDTO dto = new SchedulingUserGroupDTO();
            List<UserTypePairDTO> userTypePairDTOS = new ArrayList<>();
            dto.setOpsUserId(entry.getKey());
            dto.setOpsUserName(remoteUserService.selectNicknameById(entry.getKey()));
            dto.setPostName(remoteUserService .getPostNameByUserId(entry.getKey()));
            double durationCount = 0.0;
            for (OpsSchedulingVo schedulingDate : entry.getValue()) {
                UserTypePairDTO pairDTO = new UserTypePairDTO();
                pairDTO.setId(schedulingDate.getId());
                pairDTO.setSchedulingDate(schedulingDate.getSchedulingDate());
                pairDTO.setSchedulingType(schedulingDate.getSchedulingType());
                pairDTO.setSchedulingTypeName(schedulingDate.getSchedulingTypeName());
                durationCount += schedulingDate.getDuration();
                userTypePairDTOS.add(pairDTO);
            }
            dto.setDurationCount(durationCount);
            dto.setUserTypePairs(userTypePairDTOS);
            schedulingDateGroupDTOS.add(dto);
        }
        return schedulingDateGroupDTOS;
    }


}
