package com.zt.plat.module.qms.resource.material.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.qms.core.code.SequenceUtil;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceInfomationDO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceProductDO;
import com.zt.plat.module.qms.resource.device.service.DeviceInfomationService;
import com.zt.plat.module.qms.resource.device.service.DeviceProductService;
import com.zt.plat.module.qms.resource.material.constant.MaterialConstants;
import com.zt.plat.module.qms.resource.material.controller.vo.*;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialInfomationDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialStandardSolutionDO;
import com.zt.plat.module.qms.resource.material.dal.mapper.MaterialStandardSolutionMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.MATERIAL_STANDARD_SOLUTION_NOT_EXISTS;

/**
 * 标液,标准溶液，包含配置信息 Service 实现类
 *
 * @author 后台管理
 */
@Slf4j
@Service
@Validated
public class MaterialStandardSolutionServiceImpl implements MaterialStandardSolutionService {

    @Resource
    private MaterialStandardSolutionMapper materialStandardSolutionMapper;

    @Autowired
    private MaterialLifecycleDetailService materialLifecycleDetailService;

    @Autowired
    private MaterialLifecycleService materialLifecycleService;

    @Autowired
    private MaterialInfomationService materialInfomationService;
    @Autowired
    private SequenceUtil sequenceUtil;
    @Autowired
    private DeviceProductService deviceProductService;
    @Autowired
    private DeviceInfomationService deviceInfomationService;

    @Transactional
    @Override
    public MaterialStandardSolutionRespVO createMaterialStandardSolution(MaterialStandardSolutionSaveReqVO createReqVO) {

        Long detailId = createReqVO.getDetailId();
        Long productId = createReqVO.getProductId();
        MaterialStandardSolutionDO mtrlStandSol = BeanUtils.toBean(createReqVO, MaterialStandardSolutionDO.class);
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();
        mtrlStandSol.setMakeUserId(loginUserId).setMakeUser(loginUserNickname).setMakeDate(LocalDateTime.now());
        // 0-未标定
        mtrlStandSol.setStandardFlow("0");
        if (detailId != null) {
            // 走申请
            MaterialLifecycleDetailDO lifecycleDetail = materialLifecycleDetailService.getMaterialLifecycleDetail(detailId);
            if (lifecycleDetail == null) throw new ServiceException(1_032_160_000, "配置申请明细不存在");
            // 已提交的申请才可配置
            MaterialLifecycleDO lifecycle = materialLifecycleService.getMaterialLifecycle(lifecycleDetail.getLifecycleId());
            if (lifecycle == null) throw new ServiceException(1_032_160_000, "配置申请不存在");
            if (lifecycle.getSubmitStatus() != 1) throw new ServiceException(1_032_160_000, "配置申请未提交");
            // 已配置数量不大于申请数量
            Map<Long, Long> madeCountMap = materialLifecycleDetailService.getMadeCountMapByDetailIds(Collections.singletonList(detailId));
            if (madeCountMap.getOrDefault(detailId, 0L) >= lifecycleDetail.getInfluenceCount().intValue())
                throw new ServiceException(1_032_160_000, "已配置数量不小于申请数量");
            mtrlStandSol.setDetailId(detailId);
        }
        // 生成物料
        MaterialInfomationDO infomationDO = materialInfomationService.saveMaterialInfomationByStdSolMake(productId, mtrlStandSol);
        // 插入
        mtrlStandSol.setInfomationId(infomationDO.getId());
        materialStandardSolutionMapper.insert(mtrlStandSol);

        // 返回
        return BeanUtils.toBean(mtrlStandSol, MaterialStandardSolutionRespVO.class);
    }

    @Transactional
    @Override
    public void updateMaterialStandardSolution(MaterialStandardSolutionSaveReqVO updateReqVO) {
        MaterialStandardSolutionDO solutionDO = materialStandardSolutionMapper.selectById(updateReqVO.getId());
        if (solutionDO == null) throw exception(MATERIAL_STANDARD_SOLUTION_NOT_EXISTS);
        // 如果到期日期有变化，修改物料实例的到期日期
        if (updateReqVO.getDueDate() != null && !solutionDO.getDueDate().equals(updateReqVO.getDueDate())) {
            MaterialInfomationDO infomationDO = new MaterialInfomationDO()
                    .setId(solutionDO.getInfomationId())
                    .setExpirationDate(LocalDate.from(updateReqVO.getDueDate()));
            materialInfomationService.updateById(infomationDO);
        }
        // 更新
        MaterialStandardSolutionDO updateObj = BeanUtils.toBean(updateReqVO, MaterialStandardSolutionDO.class);
        materialStandardSolutionMapper.updateById(updateObj);
    }

    @Transactional
    @Override
    public void deleteMaterialStandardSolution(Long id) {
        MaterialStandardSolutionDO solutionDO = materialStandardSolutionMapper.selectById(id);
        if (solutionDO == null) throw exception(MATERIAL_STANDARD_SOLUTION_NOT_EXISTS);
        // 已标定的不允许删除
        if ("1".equals(solutionDO.getStandardFlow())) throw new ServiceException(1_032_160_000, "已标定的标准溶液不允许删除");
        // 删除物料
        materialInfomationService.deleteMaterialInfomation(solutionDO.getInfomationId());
        // 删除
        materialStandardSolutionMapper.deleteById(id);
    }

    @Transactional
    @Override
        public void deleteMaterialStandardSolutionListByIds(List<Long> ids) {
        List<MaterialStandardSolutionDO> solutionDOS = materialStandardSolutionMapper.selectByIds(ids);
        if (CollUtil.isEmpty(solutionDOS) || solutionDOS.size() != ids.size())
            throw exception(MATERIAL_STANDARD_SOLUTION_NOT_EXISTS);
        solutionDOS.forEach(solutionDO -> {
            // 已标定的不允许删除
            if ("1".equals(solutionDO.getStandardFlow())) throw new ServiceException(1_032_160_000, "存在已标定的标准溶液不允许删除");
        });
        // 删除物料
        List<Long> infIds = solutionDOS.stream().map(MaterialStandardSolutionDO::getInfomationId).toList();
        materialInfomationService.deleteMaterialInfomationListByIds(infIds);
        // 删除
        materialStandardSolutionMapper.deleteByIds(ids);
        }

    private void validateMaterialStandardSolutionExists(List<Long> ids) {
        List<MaterialStandardSolutionDO> list = materialStandardSolutionMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_STANDARD_SOLUTION_NOT_EXISTS);
        }
    }

    private void validateMaterialStandardSolutionExists(Long id) {
        if (materialStandardSolutionMapper.selectById(id) == null) {
            throw exception(MATERIAL_STANDARD_SOLUTION_NOT_EXISTS);
        }
    }

    @Override
    public MaterialStandardSolutionDO getMaterialStandardSolution(Long id) {
        return materialStandardSolutionMapper.selectById(id);
    }

    @Override
    public PageResult<MaterialStandardSolutionDO> getMaterialStandardSolutionPage(MaterialStandardSolutionPageReqVO pageReqVO) {
        return materialStandardSolutionMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<MaterialStandardSolutionRespVO> getStandardSolutionPageWithMaterialInfo(MaterialStandardSolutionPageReqVO pageReqVO) {

        return materialStandardSolutionMapper.selectPageWithMaterialInfo(pageReqVO);
    }

    @Override
    public Map<Long, Long> getMadeCountMapByDetailIds(List<Long> detailIds) {
        QueryWrapper<MaterialStandardSolutionDO> queryWrapper = Wrappers.query(MaterialStandardSolutionDO.class)
                .select("DTL_ID ,count(*) as quantity")
                .in("DTL_ID", detailIds)
                .groupBy("DTL_ID");
        List<Map<String, Object>> maps = materialStandardSolutionMapper.selectMaps(queryWrapper);
        log.info("maps: {}", maps);
        if (CollUtil.isEmpty(maps)) return new HashMap<>();

        return maps.stream().collect(Collectors.toMap(
                map -> (Long) map.get("DTL_ID"),
                map -> (Long) map.get("QUANTITY")
        ));
    }

    @Override
    public List<DeviceProductWithInfomationsRespVO> getDeviceBuretteProductWithInfomationList() {
        List<DeviceProductDO> deviceProducts = deviceProductService.getDeviceProductByCategoryName(MaterialConstants.DEVICE_BURETTE_CATEGORY_NAME);
        if (CollUtil.isEmpty(deviceProducts)) throw new ServiceException(1_032_160_000, "未找到滴定管设备类别");
        List<Long> devicePdtIds = deviceProducts.stream().map(DeviceProductDO::getId).toList();
        List<DeviceInfomationDO> infomationDOS = deviceInfomationService.getListByProductIdList(devicePdtIds);
        if (CollUtil.isEmpty(infomationDOS)) return List.of();
        List<DeviceInfomationRespVOBySol> respVOBySols = infomationDOS.stream().map(
                infomationDO -> {
                    DeviceInfomationRespVOBySol respVOBySol = BeanUtils.toBean(infomationDO, DeviceInfomationRespVOBySol.class);
                    respVOBySol.setName(infomationDO.getDeviceName());
                    return respVOBySol;
                }).toList();
        Map<Long, List<DeviceInfomationRespVOBySol>> infoMapByPtdId = respVOBySols.stream().collect(Collectors.groupingBy(DeviceInfomationRespVOBySol::getProductId));

        return deviceProducts.stream().map(deviceProductDO -> {
            DeviceProductWithInfomationsRespVO respVO = BeanUtils.toBean(deviceProductDO, DeviceProductWithInfomationsRespVO.class);
            respVO.setChildren(infoMapByPtdId.get(deviceProductDO.getId()));
            return respVO;
        }).toList();
    }

    @Override
    public MaterialStandardSolutionRespVO getStandardSolutionWithMaterialInfo(Long id) {
        return materialStandardSolutionMapper.selectStandardSolutionWithMaterialInfoById(id);
    }

}