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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
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.module.qms.business.config.controller.vo.MaterialAssayStandardDetailRespVO;
import com.zt.plat.module.qms.business.config.service.MaterialAssayStandardDetailService;
import com.zt.plat.module.qms.business.dic.dal.dataobject.DictionaryProjectDO;
import com.zt.plat.module.qms.business.dic.service.DictionaryProjectService;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialCorrelationAssayRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialLifecycleDetailPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialLifecycleDetailRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialLifecycleDetailSaveReqVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.*;
import com.zt.plat.module.qms.resource.material.dal.mapper.MaterialLifecycleDetailMapper;
import com.zt.plat.module.qms.resource.material.enums.MaterialFlowType;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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

/**
 * 物料通用流程明细 Service 实现类
 *
 * @author 后台管理
 */
@Slf4j
@Service
@Validated
public class MaterialLifecycleDetailServiceImpl implements MaterialLifecycleDetailService {

    @Resource
    private MaterialLifecycleDetailMapper materialLifecycleDetailMapper;
    @Autowired
    private MaterialBatchService materialBatchService;
    @Autowired
    private MaterialProductService materialProductService;
    @Autowired
    private MaterialCorrelationAssayService materialCorrelationAssayService;
    @Autowired
    private MaterialAssayStandardDetailService materialAssayStandardDetailService;

    @Override
    public MaterialLifecycleDetailRespVO createMaterialLifecycleDetail(MaterialLifecycleDetailSaveReqVO createReqVO) {
        // 插入
        MaterialLifecycleDetailDO materialLifecycleDetail = BeanUtils.toBean(createReqVO, MaterialLifecycleDetailDO.class);
        materialLifecycleDetailMapper.insert(materialLifecycleDetail);
        // 返回
        return BeanUtils.toBean(materialLifecycleDetail, MaterialLifecycleDetailRespVO.class);
    }

    @Override
    public void updateMaterialLifecycleDetail(MaterialLifecycleDetailSaveReqVO updateReqVO) {
        MaterialLifecycleDetailDO detailDO = materialLifecycleDetailMapper.selectById(updateReqVO.getId());
        if (detailDO == null) throw exception(MATERIAL_LIFECYCLE_DETAIL_NOT_EXISTS);
        // 更新
        MaterialFlowType flowType = MaterialFlowType.fromName(detailDO.getBusinessType());
        if (MaterialFlowType.verify_calibrate.equals(flowType)) {
            // 合格数量不大于总数量
            BigDecimal qualifiedCount = updateReqVO.getQualifiedCount();
            if (qualifiedCount == null) throw new ServiceException(1_032_160_000, "请填写合格数量");
            if (qualifiedCount.compareTo(detailDO.getInfluenceCount()) > 0)
                throw new ServiceException(1_032_160_000, "合格数量不能大于总数量");
            detailDO.setQualifiedCount(qualifiedCount);
            detailDO.setUnqualifiedCount(detailDO.getInfluenceCount().subtract(detailDO.getQualifiedCount()));
        }
        materialLifecycleDetailMapper.updateById(detailDO);
    }

    @Override
    public void deleteMaterialLifecycleDetail(Long id) {
        // 校验存在
        validateMaterialLifecycleDetailExists(id);
        // 删除
        materialLifecycleDetailMapper.deleteById(id);
    }

    @Override
        public void deleteMaterialLifecycleDetailListByIds(List<Long> ids) {
        // 校验存在
        validateMaterialLifecycleDetailExists(ids);
        // 删除
        materialLifecycleDetailMapper.deleteByIds(ids);
        }

    private void validateMaterialLifecycleDetailExists(List<Long> ids) {
        List<MaterialLifecycleDetailDO> list = materialLifecycleDetailMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_LIFECYCLE_DETAIL_NOT_EXISTS);
        }
    }

    private void validateMaterialLifecycleDetailExists(Long id) {
        if (materialLifecycleDetailMapper.selectById(id) == null) {
            throw exception(MATERIAL_LIFECYCLE_DETAIL_NOT_EXISTS);
        }
    }

    @Override
    public MaterialLifecycleDetailDO getMaterialLifecycleDetail(Long id) {
        return materialLifecycleDetailMapper.selectById(id);
    }

    @Override
    public PageResult<MaterialLifecycleDetailDO> getMaterialLifecycleDetailPage(MaterialLifecycleDetailPageReqVO pageReqVO) {
        return materialLifecycleDetailMapper.selectPage(pageReqVO);
    }

    @Override
    public void saveBatch(List<MaterialLifecycleDetailDO> detailDOS) {
        if (CollUtil.isEmpty(detailDOS)) return;
        materialLifecycleDetailMapper.insertBatch(detailDOS);
    }

    @Override
    public void deleteLifecycleDetailListByLfcId(Long lfcId) {
        materialLifecycleDetailMapper.delete(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .eq(MaterialLifecycleDetailDO::getLifecycleId, lfcId));
    }


    @Override
    public void deleteLifecycleDetailListByLfcIds(List<Long> ids) {
        materialLifecycleDetailMapper.delete(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .in(MaterialLifecycleDetailDO::getLifecycleId, ids));
    }

    @Override
    public List<MaterialLifecycleDetailRespVO> getDetailListWithPdtInfoByLfcId(MaterialLifecycleDO lifecycleDO) {
        // 退换货时单独处理
        MaterialFlowType flowType = MaterialFlowType.fromName(lifecycleDO.getBusinessType());
        switch (flowType) {
            case acceptance -> {
                List<MaterialLifecycleDetailRespVO> details = materialLifecycleDetailMapper.selectListWithGongPdtBatInfo(lifecycleDO.getId());
                if (CollUtil.isEmpty(details)) return details;
                // 有检化验的需要处理
                List<MaterialLifecycleDetailRespVO> assayDetails = details.stream().filter(detail -> detail.getAssayId() != null).toList();
                if (CollUtil.isEmpty(assayDetails)) return details;
                List<Long> asyIds = assayDetails.stream().map(MaterialLifecycleDetailRespVO::getAssayId).toList();
                List<MaterialCorrelationAssayRespVO> assayRespVOS = materialCorrelationAssayService.getRespListByIds(asyIds);
                if (CollUtil.isEmpty(assayRespVOS)) return details;
                // 获取检测项显示名称
                List<Long> allItemIds = assayRespVOS.stream().map(MaterialCorrelationAssayRespVO::getItems)
                        .flatMap(Collection::stream).toList();
                if (CollUtil.isEmpty(allItemIds)) return details;
                List<MaterialAssayStandardDetailRespVO> allItems = materialAssayStandardDetailService.getListWithExtendByIds(allItemIds);
                assert CollUtil.isNotEmpty(allItems);
                Map<Long, MaterialAssayStandardDetailRespVO> itemMapById = allItems.stream().collect(Collectors.toMap(MaterialAssayStandardDetailRespVO::getId, Function.identity()));
                assayRespVOS.forEach(asy -> {
                    List<String> showNames = asy.getItems().stream()
                            .map(itemMapById::get)
                            .filter(Objects::nonNull)
                            .map(MaterialAssayStandardDetailRespVO::getDictionaryProjectShowName)
                            .toList();
                    asy.setItemsShowName(String.join(",", showNames));
                });
                Map<Long, MaterialCorrelationAssayRespVO> assayRespVOMapById = assayRespVOS.stream().collect(Collectors.toMap(MaterialCorrelationAssayRespVO::getId, Function.identity()));
                details.forEach(detail -> {
                    MaterialCorrelationAssayRespVO assayRespVO = assayRespVOMapById.get(detail.getAssayId());
                    detail.setAssayInfo(assayRespVO);
                });
                return details;
            }
            case verify_calibrate -> {
                return materialLifecycleDetailMapper.selectListWithBatchPdtBatInfo(lifecycleDO.getId());
            }
            case return_material, replace_material -> {
                List<MaterialLifecycleDetailRespVO> detailRespVOS = materialLifecycleDetailMapper.selectListWithReturnExchangeInfo(lifecycleDO.getId());
                if (CollUtil.isEmpty(detailRespVOS)) return detailRespVOS;
                List<Long> batOrGongIds = detailRespVOS.stream()
                        .flatMap(detail -> Stream.of(detail.getBatchId(), detail.getBatchGongduanId()).filter(Objects::nonNull))
                        .toList();
                List<MaterialBatchDO> batOrGongDOS = materialBatchService.getListByIds(batOrGongIds);
                if (CollUtil.isEmpty(batOrGongDOS)) return detailRespVOS;
                Set<Long> pdtIds = batOrGongDOS.stream().map(MaterialBatchDO::getProductId).collect(Collectors.toSet());
                List<MaterialProductDO> products = materialProductService.getListByIds(new ArrayList<>(pdtIds));
                if (CollUtil.isEmpty(products)) return detailRespVOS;
                Map<Long, MaterialBatchDO> batOrGongMapById = batOrGongDOS.stream().collect(Collectors.toMap(MaterialBatchDO::getId, Function.identity()));
                Map<Long, MaterialProductDO> productMapById = products.stream().collect(Collectors.toMap(MaterialProductDO::getId, Function.identity()));
                for (MaterialLifecycleDetailRespVO detailRespVO : detailRespVOS) {
                    MaterialProductDO productDO = new MaterialProductDO();
                    if (detailRespVO.getBatchId() != null) {
                        MaterialBatchDO batchDO = batOrGongMapById.get(detailRespVO.getBatchId());
                        detailRespVO.setGongParentId(0L);
                        detailRespVO.setInboundQuantity(batchDO.getInboundQuantity());
                        productDO = productMapById.get(batchDO.getProductId());
                    } else if (detailRespVO.getBatchGongduanId() != null) {
                        MaterialBatchDO gongDO = batOrGongMapById.get(detailRespVO.getBatchGongduanId());
                        detailRespVO.setGongParentId(gongDO.getParentId());
                        detailRespVO.setBatchNo(gongDO.getBatchNo());
                        detailRespVO.setInboundQuantity(gongDO.getInboundQuantity());
                        productDO = productMapById.get(gongDO.getProductId());
                    }
                    detailRespVO
                            .setProductId(productDO.getId())
                            .setProductName(productDO.getName())
                            .setProductCode(productDO.getCode())
                            .setProductSpecification(productDO.getSpecification())
                            .setProductModelNo(productDO.getModelNo());
                }
                return detailRespVOS;
            }
        }

        return List.of();
    }


    @Override
    public MaterialLifecycleDetailDO getMaterialLifecycleDetailByGongId(Long gongduanId) {
        List<MaterialLifecycleDetailDO> detailDOS = materialLifecycleDetailMapper.selectList(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .eq(MaterialLifecycleDetailDO::getBatchGongduanId, gongduanId)
                .last("limit 1"));
        if (CollUtil.isEmpty(detailDOS)) return null;
        return detailDOS.get(0);
    }

    @Override
    public void updateDetailTreatStatusByLfcId(Long lfcId, Boolean isTreat) {
        MaterialLifecycleDetailDO detailUpdate = new MaterialLifecycleDetailDO().setTreatmentStatus(isTreat ? 1 : 0);
        materialLifecycleDetailMapper.update(detailUpdate, Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .eq(MaterialLifecycleDetailDO::getLifecycleId, lfcId));
    }

    @Override
    public List<MaterialLifecycleDetailDO> getDetailListByLfcId(Long lfcId) {

        return materialLifecycleDetailMapper.selectList(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .eq(MaterialLifecycleDetailDO::getLifecycleId, lfcId));
    }

    @Override
    public List<MaterialLifecycleDetailRespVO> getNotMakeLifecycleDetailList(MaterialLifecycleDetailPageReqVO reqVO) {
        return materialLifecycleDetailMapper.selectNotMakeList(reqVO);
    }

    @Override
    public List<MaterialLifecycleDetailRespVO> getDetailRespVOListByLfcIds(List<Long> lfcIds) {
        return materialLifecycleDetailMapper.selectDetailRespVOListByLfcIds(lfcIds);
    }

    @Override
    public Map<Long, Long> getMadeCountMapByDetailIds(List<Long> detailIds) {

        return materialLifecycleDetailMapper.getMadeCountMapByDetailIds(detailIds);
    }

    @Override
    public List<MaterialLifecycleDetailDO> getDetailListByLfcIds(List<Long> lfcIds) {
        return materialLifecycleDetailMapper.selectList(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .in(MaterialLifecycleDetailDO::getLifecycleId, lfcIds));
    }

    @Override
    public void updateBatchMaterialLifecycleDetail(List<MaterialLifecycleDetailSaveReqVO> updateReqVOS) {
        List<MaterialLifecycleDetailDO> reqDetailDOS = BeanUtils.toBean(updateReqVOS, MaterialLifecycleDetailDO.class);
        List<Long> dtlIds = reqDetailDOS.stream().map(MaterialLifecycleDetailDO::getId).filter(Objects::nonNull).toList();
        if (CollUtil.isEmpty(dtlIds) || dtlIds.size() != updateReqVOS.size())
            throw new ServiceException(1_032_160_000, "存在id为空的请求数据");
        List<MaterialLifecycleDetailDO> detailDOS = materialLifecycleDetailMapper.selectByIds(dtlIds);
        if (CollUtil.isEmpty(detailDOS) || detailDOS.size() != dtlIds.size())
            throw exception(MATERIAL_LIFECYCLE_DETAIL_NOT_EXISTS);
        Map<String, List<MaterialLifecycleDetailDO>> detailGroupByBusinessType = detailDOS.stream().collect(Collectors.groupingBy(MaterialLifecycleDetailDO::getBusinessType));
        List<MaterialLifecycleDetailDO> verifyDetailDOS = detailGroupByBusinessType.get(MaterialFlowType.verify_calibrate.getName());
        // 检定校准
        if (CollUtil.isNotEmpty(verifyDetailDOS)) {
            Map<Long, MaterialLifecycleDetailDO> verifyDetailDOMapById = verifyDetailDOS.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getId, Function.identity()));
            Map<Long, MaterialLifecycleDetailDO> reqDOMapById = reqDetailDOS.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getId, Function.identity()));
            for (MaterialLifecycleDetailDO detailDO : reqDetailDOS) {
                BigDecimal qualifiedCount = reqDOMapById.get(detailDO.getId()).getQualifiedCount();
                MaterialLifecycleDetailDO verifyDetailDO = verifyDetailDOMapById.get(detailDO.getId());
                if (qualifiedCount == null) throw new ServiceException(1_032_160_000, "请填写合格数量");
                BigDecimal influenceCount = verifyDetailDO.getInfluenceCount();
                if (qualifiedCount.compareTo(influenceCount) > 0)
                    throw new ServiceException(1_032_160_000, "合格数量不能大于总数量");
                detailDO.setQualifiedCount(qualifiedCount);
                detailDO.setUnqualifiedCount(influenceCount.subtract(detailDO.getQualifiedCount()));
            }

            materialLifecycleDetailMapper.updateBatch(reqDetailDOS);
        }
    }

    @Override
    public void updateBatch(List<MaterialLifecycleDetailDO> assayDetails) {
        materialLifecycleDetailMapper.updateBatch(assayDetails);
    }

    @Override
    public List<MaterialLifecycleDetailDO> getDetailListByAsyId(Long id) {

        return materialLifecycleDetailMapper.selectList(Wrappers.lambdaQuery(MaterialLifecycleDetailDO.class)
                .eq(MaterialLifecycleDetailDO::getAssayId, id));
    }

}