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

import cn.hutool.core.collection.CollUtil;
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.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.MaterialProductDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialUseEndReuseDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialUseEndReuseDetailDO;
import com.zt.plat.module.qms.resource.material.dal.mapper.MaterialUseEndReuseMapper;
import com.zt.plat.module.qms.resource.material.enums.MaterialNormalOperationType;
import jakarta.annotation.Resource;
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.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
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_USE_END_REUSE_NOT_EXISTS;

/**
 * 物料用完标记或清洗回收 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class MaterialUseEndReuseServiceImpl implements MaterialUseEndReuseService {

    @Resource
    private MaterialUseEndReuseMapper materialUseEndReuseMapper;

    @Autowired
    private MaterialUseEndReuseDetailService materialUseEndReuseDetailService;
    @Autowired
    private MaterialInfomationService materialInfomationService;
    @Autowired
    private MaterialProductService materialProductService;

    @Transactional
    @Override
    public MaterialUseEndReuseRespVO createMaterialUseEndReuse(MaterialUseEndReuseSaveReqVO createReqVO) {
        List<MaterialUseEndReuseDetailSaveReqVO> detailList = createReqVO.getDetailList();
        MaterialNormalOperationType operationType = MaterialNormalOperationType.fromName(createReqVO.getBusinessType());

        List<Long> infomationIds = detailList.stream().map(MaterialUseEndReuseDetailSaveReqVO::getInfomationId)
                .filter(Objects::nonNull).toList();
        // 用完标记 开封
        if (MaterialNormalOperationType.used_mark.equals(operationType) || MaterialNormalOperationType.open_seal.equals(operationType)) {
            if (CollUtil.isEmpty(infomationIds)) throw new ServiceException(1_032_160_000,
                    String.format("【%s】的物料实例不能为空", MaterialNormalOperationType.used_mark == operationType ? "用完标记" : "开封"));
            List<MaterialInfomationDO> infomations = materialInfomationService.getListByIds(infomationIds);
            if (CollUtil.isEmpty(infomations) || infomations.size() != infomationIds.size())
                throw new ServiceException(1_032_160_000, "物料实例不存在或与传入的数量不匹配");
        }

        // 插入
        MaterialUseEndReuseDO useEndReuseDO = BeanUtils.toBean(createReqVO, MaterialUseEndReuseDO.class);

        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();

        useEndReuseDO.setOperatorId(loginUserId).setOperator(loginUserNickname)
                .setOperatorDate(LocalDateTime.now());

        if (MaterialNormalOperationType.open_seal.equals(operationType)) {
            // 开封时间从前端传
            useEndReuseDO.setOperatorDate(createReqVO.getOperatorDate());
        }

        materialUseEndReuseMapper.insert(useEndReuseDO);

        // 保存明细
        List<MaterialUseEndReuseDetailDO> detailDOS = detailList.stream().map(detail -> {
            MaterialUseEndReuseDetailDO detailDO = BeanUtils.toBean(detail, MaterialUseEndReuseDetailDO.class);
            detailDO.setParentId(useEndReuseDO.getId()).setTreatmentStatus("0");
            return detailDO;
        }).toList();
        materialUseEndReuseDetailService.saveBatch(detailDOS);

        // 变更物料用完标记状态
        if (MaterialNormalOperationType.used_mark.equals(operationType) && CollUtil.isNotEmpty(infomationIds)) {
            materialInfomationService.updateByIds(infomationIds, new MaterialInfomationDO().setUseEndFlag(1));
        }
        // 开封处理
        if (MaterialNormalOperationType.open_seal.equals(operationType)) {
            materialInfomationService.openSealTreatment(infomationIds, useEndReuseDO);
        }
        // 返回
        return BeanUtils.toBean(useEndReuseDO, MaterialUseEndReuseRespVO.class);
    }

    @Override
    public void updateMaterialUseEndReuse(MaterialUseEndReuseSaveReqVO updateReqVO) {
        // 校验存在
        validateMaterialUseEndReuseExists(updateReqVO.getId());
        // 更新
        MaterialUseEndReuseDO updateObj = BeanUtils.toBean(updateReqVO, MaterialUseEndReuseDO.class);
        materialUseEndReuseMapper.updateById(updateObj);
    }

    @Transactional
    @Override
    public void deleteMaterialUseEndReuse(Long id) {
        MaterialUseEndReuseDO useEndReuseDO = materialUseEndReuseMapper.selectById(id);
        if (useEndReuseDO == null) throw exception(MATERIAL_USE_END_REUSE_NOT_EXISTS);
        // 用完标记不可删除
        if (MaterialNormalOperationType.used_mark.getName().equals(useEndReuseDO.getBusinessType()))
            throw new ServiceException(1_032_160_000, "用完标记记录不可删除");
        // 删除明细
        materialUseEndReuseDetailService.deleteDetailListByParentId(id);
        // 删除
        materialUseEndReuseMapper.deleteById(id);
    }

    @Transactional
    @Override
        public void deleteMaterialUseEndReuseListByIds(List<Long> ids) {
        List<MaterialUseEndReuseDO> useEndReuseDOS = materialUseEndReuseMapper.selectByIds(ids);
        if (CollUtil.isEmpty(useEndReuseDOS) || useEndReuseDOS.size() != ids.size()) {
            throw exception(MATERIAL_USE_END_REUSE_NOT_EXISTS);
        }
        for (MaterialUseEndReuseDO useEndReuseDO : useEndReuseDOS) {
            // 用完标记不可删除
            if (MaterialNormalOperationType.used_mark.getName().equals(useEndReuseDO.getBusinessType()))
                throw new ServiceException(1_032_160_000, "用完标记记录不可删除");
        }
        // 删除明细
        List<Long> useIds = useEndReuseDOS.stream().map(MaterialUseEndReuseDO::getId).toList();
        materialUseEndReuseDetailService.deleteDetailListByParentIds(useIds);
        // 删除
        materialUseEndReuseMapper.deleteByIds(ids);
        }

    private void validateMaterialUseEndReuseExists(List<Long> ids) {
        List<MaterialUseEndReuseDO> list = materialUseEndReuseMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_USE_END_REUSE_NOT_EXISTS);
        }
    }

    private void validateMaterialUseEndReuseExists(Long id) {
        if (materialUseEndReuseMapper.selectById(id) == null) {
            throw exception(MATERIAL_USE_END_REUSE_NOT_EXISTS);
        }
    }

    @Override
    public MaterialUseEndReuseDO getMaterialUseEndReuse(Long id) {
        return materialUseEndReuseMapper.selectById(id);
    }

    @Override
    public PageResult<MaterialUseEndReuseDO> getMaterialUseEndReusePage(MaterialUseEndReusePageReqVO pageReqVO) {
        return materialUseEndReuseMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<MaterialUseEndReuseRespVO> getPageWithDetail(MaterialUseEndReusePageReqVO pageReqVO) {
        Long productId = pageReqVO.getProductId();
        PageResult<MaterialUseEndReuseDO> pageResult;
        if (productId == null) {
            pageResult = materialUseEndReuseMapper.selectPage(pageReqVO);
        } else {
            List<MaterialProductDO> products = materialProductService.getMaterialProductsByLikeIdPath(productId);
            if (CollUtil.isEmpty(products)) {
                pageResult = materialUseEndReuseMapper.selectPage(pageReqVO);
            } else {
                List<Long> pdtIds = products.stream().map(MaterialProductDO::getId).toList();
                pageResult = materialUseEndReuseMapper.selectPage(pageReqVO, pdtIds);
            }
        }
        List<MaterialUseEndReuseDO> useEndReuseDOS = pageResult.getList();
        if (CollUtil.isEmpty(useEndReuseDOS)) return PageResult.empty();
        List<Long> useIds = useEndReuseDOS.stream().map(MaterialUseEndReuseDO::getId).toList();

        PageResult<MaterialUseEndReuseRespVO> respVOPageResult = BeanUtils.toBean(pageResult, MaterialUseEndReuseRespVO.class);

        List<MaterialUseEndReuseDetailRespVO> detailRespVOS = materialUseEndReuseDetailService.getDetailRespVOSByParentIds(useIds);
        if (CollUtil.isEmpty(detailRespVOS)) return respVOPageResult;
        Map<Long, List<MaterialUseEndReuseDetailRespVO>> detailRespVOMapByParentId = detailRespVOS.stream().collect(Collectors.groupingBy(MaterialUseEndReuseDetailRespVO::getParentId));
        List<MaterialUseEndReuseRespVO> list = respVOPageResult.getList();
        for (MaterialUseEndReuseRespVO useEndReuseRespVO : list) {
            useEndReuseRespVO.setChildren(detailRespVOMapByParentId.get(useEndReuseRespVO.getId()));
        }
        respVOPageResult.setList(list);
        return respVOPageResult;
    }

    @Transactional
    @Override
    public void reuseMaterialsByDetailIds(List<Long> detailIds) {
        List<MaterialUseEndReuseDetailDO> detailDOS = materialUseEndReuseDetailService.getDetailListByIds(detailIds);
        if (CollUtil.isEmpty(detailDOS)) throw new ServiceException(1_032_160_000, "回收的物料不存在");
        // 检查回收状态
        for (MaterialUseEndReuseDetailDO detailDO : detailDOS) {
            if ("1".equals(detailDO.getTreatmentStatus()))
                throw new ServiceException(1_032_160_000, String.format("物料【%s】已回收", detailDO.getMaterialName()));
        }
        List<Long> reuseIds = detailDOS.stream().map(MaterialUseEndReuseDetailDO::getParentId).toList();
        LocalDateTime reuseDate = LocalDateTime.now();
        materialUseEndReuseDetailService.updateByIds(detailIds,
                new MaterialUseEndReuseDetailDO().setTreatmentStatus("1").setReuseDate(reuseDate));
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();
        this.updateByIds(reuseIds, new MaterialUseEndReuseDO().setReuseId(loginUserId).setReuseName(loginUserNickname)
                .setReuseDate(reuseDate));
    }

    @Override
    public void updateByIds(List<Long> reuseIds, MaterialUseEndReuseDO useEndReuseDO) {
        materialUseEndReuseMapper.update(useEndReuseDO, Wrappers.lambdaQuery(MaterialUseEndReuseDO.class)
                .in(MaterialUseEndReuseDO::getId, reuseIds));
    }

}