package cn.iocoder.yudao.module.system.service.biz;

import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.BedPlanRecordEffectiveQueryReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.BedPlanRecordEffectiveRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.BedPlanRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.BedPlanRecordSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.BedPlanRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.BuildDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.BuildFloorDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.BedPlanRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.biz.BuildFloorMapper;
import cn.iocoder.yudao.module.system.dal.mysql.biz.BuildMapper;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_ERROR;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_EXIST_ERROR;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_NOT_FOUND;

/**
 * 床位计划记录 Service 实现类
 */
@Service
@Validated
public class BedPlanRecordServiceImpl implements BedPlanRecordService {

    @Resource
    private BedPlanRecordMapper bedPlanRecordMapper;
    @Resource
    private BuildMapper buildMapper;
    @Resource
    private BuildFloorMapper buildFloorMapper;

    @Override
    @Transactional
    public Integer createBedPlanRecord(BedPlanRecordSaveReqVO createReqVO) {
        if (CollUtil.isEmpty(createReqVO.getBuildFloorBedCountVOList())) {
            throw ServiceExceptionUtil.exception(COMMON_ERROR);
        }
        List<BedPlanRecordDO> addList = new ArrayList<>();
        for (BedPlanRecordSaveReqVO.BuildFloorBedCountVO buildFloorBedCountVO : createReqVO.getBuildFloorBedCountVOList()) {
            for (BedPlanRecordSaveReqVO.FloorBedCountVO floorBedCountVO : buildFloorBedCountVO.getFloorBedCountVOList()) {
                BedPlanRecordDO recordDO = BeanUtils.toBean(createReqVO, BedPlanRecordDO.class);
                recordDO.setBuildId(buildFloorBedCountVO.getBuildId());
                recordDO.setFloorId(floorBedCountVO.getFloorId());
                recordDO.setBedCount(floorBedCountVO.getBedCount());
                // 校验生效期重叠
                Long overlap = bedPlanRecordMapper.selectOverlapCount(recordDO.getBuildId(),
                        recordDO.getFloorId(), recordDO.getBeginYearMonth(), recordDO.getEndYearMonth(),
                        recordDO.getTenantId());
                if (overlap != null && overlap > 0) {
                    throw ServiceExceptionUtil.exception(COMMON_EXIST_ERROR);
                }
                addList.add(recordDO);
            }
        }
        bedPlanRecordMapper.insertBatch(addList);
        return addList.size();
    }

    @Override
    @Transactional
    public void updateBedPlanRecord(BedPlanRecordSaveReqVO updateReqVO) {
        if (CollUtil.isEmpty(updateReqVO.getBuildFloorBedCountVOList())) {
            throw ServiceExceptionUtil.exception(COMMON_ERROR);
        }
        Long targetTenantId = updateReqVO.getTenantId() == null ? TenantContextHolder.getTenantId() : updateReqVO.getTenantId();
        // 删除旧方案
        bedPlanRecordMapper.delete(new LambdaQueryWrapperX<BedPlanRecordDO>()
                .eq(BedPlanRecordDO::getPlanSeq, updateReqVO.getPlanSeq())
                .eq(BedPlanRecordDO::getBeginYearMonth, updateReqVO.getBeginYearMonth())
                .eq(BedPlanRecordDO::getEndYearMonth, updateReqVO.getEndYearMonth())
                .eq(BedPlanRecordDO::getTenantId, updateReqVO.getTenantId()));
        // 按新入参重新写入
        List<BedPlanRecordDO> addList = new ArrayList<>();
        for (BedPlanRecordSaveReqVO.BuildFloorBedCountVO buildFloorBedCountVO : updateReqVO.getBuildFloorBedCountVOList()) {
            for (BedPlanRecordSaveReqVO.FloorBedCountVO floorBedCountVO : buildFloorBedCountVO.getFloorBedCountVOList()) {
                BedPlanRecordDO recordDO = BeanUtils.toBean(updateReqVO, BedPlanRecordDO.class);
                recordDO.setTenantId(targetTenantId);
                recordDO.setBuildId(buildFloorBedCountVO.getBuildId());
                recordDO.setFloorId(floorBedCountVO.getFloorId());
                recordDO.setBedCount(floorBedCountVO.getBedCount());
                Long overlap = bedPlanRecordMapper.selectOverlapCount(recordDO.getBuildId(),
                        recordDO.getFloorId(), recordDO.getBeginYearMonth(), recordDO.getEndYearMonth(),
                        recordDO.getTenantId());
                if (overlap != null && overlap > 0) {
                    throw ServiceExceptionUtil.exception(COMMON_EXIST_ERROR);
                }
                addList.add(recordDO);
            }
        }
        if (CollUtil.isNotEmpty(addList)) {
            bedPlanRecordMapper.insertBatch(addList);
        }
    }

    @Override
    public void deleteBedPlanRecord(Long id) {
        validateExists(id);
        bedPlanRecordMapper.deleteById(id);
    }

    @Override
    public BedPlanRecordDO getBedPlanRecord(Long id) {
        return bedPlanRecordMapper.selectById(id);
    }

    @Override
    public PageResult<BedPlanRecordDO> getBedPlanRecordPage(BedPlanRecordPageReqVO pageReqVO) {
        return bedPlanRecordMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BedPlanRecordEffectiveRespVO> getEffectiveList(BedPlanRecordEffectiveQueryReqVO reqVO) {
        List<BedPlanRecordDO> list = bedPlanRecordMapper.selectEffectiveList(reqVO);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        Set<Long> buildIds = list.stream().map(BedPlanRecordDO::getBuildId).collect(Collectors.toSet());
        Set<Long> floorIds = list.stream().map(BedPlanRecordDO::getFloorId).collect(Collectors.toSet());
        Map<Long, String> buildNameMap = buildMapper.selectBatchIds(buildIds).stream()
                .collect(Collectors.toMap(BuildDO::getId, BuildDO::getBuildName, (a, b) -> a));
        Map<Long, String> floorNameMap = buildFloorMapper.selectBatchIds(floorIds).stream()
                .collect(Collectors.toMap(BuildFloorDO::getId, BuildFloorDO::getFloorName, (a, b) -> a));
        HashMap<String, BedPlanRecordEffectiveRespVO> map = new HashMap<>();
        for (BedPlanRecordDO item : list) {
            String key = item.getBeginYearMonth() + "|" + item.getEndYearMonth() + "|" + item.getPlanSeq() + "|" + item.getTenantId();
            BedPlanRecordEffectiveRespVO respVO = map.computeIfAbsent(key, k -> {
                BedPlanRecordEffectiveRespVO vo = new BedPlanRecordEffectiveRespVO();
                vo.setBuildFloorBedCountVOList(new ArrayList<>());
                vo.setPlanSeq(item.getPlanSeq());
                vo.setBeginYearMonth(item.getBeginYearMonth());
                vo.setEndYearMonth(item.getEndYearMonth());
                vo.setTenantId(item.getTenantId());
                return vo;
            });
            // 找到或创建楼栋节点
            BedPlanRecordEffectiveRespVO.BuildFloorBedCountVO buildNode = respVO.getBuildFloorBedCountVOList().stream()
                    .filter(b -> b.getBuildId().equals(item.getBuildId()))
                    .findFirst()
                    .orElseGet(() -> {
                        BedPlanRecordEffectiveRespVO.BuildFloorBedCountVO vo = new BedPlanRecordEffectiveRespVO.BuildFloorBedCountVO();
                        vo.setBuildId(item.getBuildId());
                        vo.setBuildName(buildNameMap.get(item.getBuildId()));
                        vo.setFloorBedCountVOList(new ArrayList<>());
                        respVO.getBuildFloorBedCountVOList().add(vo);
                        return vo;
                    });
            BedPlanRecordSaveReqVO.FloorBedCountVO floorVO = new BedPlanRecordSaveReqVO.FloorBedCountVO();
            floorVO.setFloorId(item.getFloorId());
            floorVO.setBedCount(item.getBedCount());
            floorVO.setFloorName(floorNameMap.get(item.getFloorId()));
            buildNode.getFloorBedCountVOList().add(floorVO);
        }
        return map.values().stream()
                .sorted((a, b) -> {
                    int cmp = a.getPlanSeq().compareTo(b.getPlanSeq());
                    if (cmp != 0) return cmp;
                    return a.getBeginYearMonth().compareTo(b.getBeginYearMonth());
                })
                .collect(Collectors.toList());
    }

    private void validateExists(Long id) {
        if (bedPlanRecordMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(COMMON_NOT_FOUND);
        }
    }
}


