package cn.iocoder.yudao.module.mes.service.itemrequisition;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import cn.iocoder.yudao.module.mes.controller.admin.itemrequisition.vo.ItemRequisitionDetailRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.itemrequisition.vo.ItemRequisitionPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.itemrequisition.vo.ItemRequisitionSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.itemrequisition.ItemRequisitionDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.itemrequisition.ItemRequisitionDetailDO;
import cn.iocoder.yudao.module.mes.dal.mysql.itemrequisition.ItemRequisitionDetailMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.itemrequisition.ItemRequisitionMapper;
import cn.iocoder.yudao.module.mes.dal.redis.no.MesNoRedisDAO;
import cn.iocoder.yudao.module.mes.service.feedingplan.FeedingRecordPlanService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PURCHASE_ORDER_NO_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.ITEM_REQUISITION_NOT_EXISTS;

/**
 * 生产领料 Service 实现类
 *
 * @author 内蒙必硕
 */
@Service
@Validated
public class ItemRequisitionServiceImpl implements ItemRequisitionService {

    @Resource
    private ItemRequisitionMapper itemRequisitionMapper;
    @Resource
    private ItemRequisitionDetailMapper itemRequisitionDetailMapper;
    @Resource
    private MesNoRedisDAO noRedisDAO;
    @Resource
    private ErpProductService productService;
    @Resource
    private ErpProductUnitService productUnitService;
    @Resource
    private FeedingRecordPlanService recordPlanService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createItemRequisition(ItemRequisitionSaveReqVO createReqVO) {
        //查询是否已存在派工领料单
        ItemRequisitionDO itemRequisitionDO = itemRequisitionMapper.selectByPlanId(createReqVO.getPlanId());
        if (itemRequisitionDO != null)
            throw exception(new ErrorCode(500, "创建领料单失败，计划已存在领料单！"));
        // 插入
        ItemRequisitionDO itemRequisition = BeanUtils.toBean(createReqVO, ItemRequisitionDO.class);
        if (StringUtils.isEmpty(itemRequisition.getCode())) {
            // 1.4 生成订单号，并校验唯一性
            String no = noRedisDAO.generate2(MesNoRedisDAO.ITEM_REQUISITION_NO_PREFIX);
            if (itemRequisitionMapper.selectByNo(no) != null) {
                throw exception(PURCHASE_ORDER_NO_EXISTS);
            }
            itemRequisition.setCode(no);
        }
        itemRequisitionMapper.insert(itemRequisition);

        // 插入子表
        createItemRequisitionDetailList(itemRequisition.getId(), createReqVO.getItemRequisitionDetails());
        // 返回
        return itemRequisition.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateItemRequisition(ItemRequisitionSaveReqVO updateReqVO) {
        // 校验存在
        validateItemRequisitionExists(updateReqVO.getId());
        // 更新
        ItemRequisitionDO updateObj = BeanUtils.toBean(updateReqVO, ItemRequisitionDO.class);
        itemRequisitionMapper.updateById(updateObj);

        // 更新子表
        updateItemRequisitionDetailList(updateReqVO.getId(), updateReqVO.getItemRequisitionDetails());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteItemRequisition(Long id) {
        // 校验存在
        validateItemRequisitionExists(id);
        // 删除
        itemRequisitionMapper.deleteById(id);

        // 删除子表
        deleteItemRequisitionDetailByItemRequisitionId(id);
    }

    private void validateItemRequisitionExists(Long id) {
        if (itemRequisitionMapper.selectById(id) == null) {
            throw exception(ITEM_REQUISITION_NOT_EXISTS);
        }
    }

    @Override
    public ItemRequisitionDO getItemRequisition(Long id) {
        return itemRequisitionMapper.selectById(id);
    }

    @Override
    public ItemRequisitionDO getItemRequisitionByPlanId(Long planId) {
        return itemRequisitionMapper.selectByPlanId(planId);
    }

    @Override
    public PageResult<ItemRequisitionDO> getItemRequisitionPage(ItemRequisitionPageReqVO pageReqVO) {
        return itemRequisitionMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（领料明细） ====================

    @Override
    public List<ItemRequisitionDetailDO> getItemRequisitionDetailListByItemRequisitionId(Long itemRequisitionId) {
        return itemRequisitionDetailMapper.selectListByItemRequisitionId(itemRequisitionId);
    }

    @Override
    public List<ItemRequisitionDetailRespVO> buildDetailVOList(List<ItemRequisitionDetailDO> list, Long planId) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, ErpProductDO> map = productService.getProductMap(
                convertSet(list, ItemRequisitionDetailDO::getProductId));
        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
                convertSet(list, ItemRequisitionDetailDO::getUnitId));

        return BeanUtils.toBean(list, ItemRequisitionDetailRespVO.class, item -> {
            MapUtils.findAndThen(map, item.getProductId(),
                    product -> item.setProductName(product.getName()));
            MapUtils.findAndThen(unitMap, item.getUnitId(),
                    unit -> item.setUnitName(unit.getName()));
            BigDecimal finish = recordPlanService.selectSumBy(planId, item.getProductId());
            item.setFinishNumber(finish);
        });
    }

    private void createItemRequisitionDetailList(Long itemRequisitionId, List<ItemRequisitionDetailDO> list) {
        list.forEach(o -> o.setItemRequisitionId(itemRequisitionId));
        itemRequisitionDetailMapper.insertBatch(list);
    }

    private void updateItemRequisitionDetailList(Long itemRequisitionId, List<ItemRequisitionDetailDO> list) {
        deleteItemRequisitionDetailByItemRequisitionId(itemRequisitionId);
        list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createItemRequisitionDetailList(itemRequisitionId, list);
    }

    private void deleteItemRequisitionDetailByItemRequisitionId(Long itemRequisitionId) {
        itemRequisitionDetailMapper.deleteByItemRequisitionId(itemRequisitionId);
    }

    @Override
    public ItemRequisitionDetailRespVO getItemRequisitionDetailRespVO(Long planId, Long itemId) {
        ItemRequisitionDO itemRequisitionDO = itemRequisitionMapper.selectByPlanId(planId);
        if (itemRequisitionDO != null) {
            ItemRequisitionDetailDO detailDO =
                    itemRequisitionDetailMapper.selectBy(itemRequisitionDO.getId(), itemId);
            if (detailDO == null) return null;
            ItemRequisitionDetailRespVO respVO = new ItemRequisitionDetailRespVO()
                    .setItemRequisitionId(itemRequisitionDO.getId())
                    .setUnitId(detailDO.getUnitId())
                    .setNumber(detailDO.getNumber())
                    .setProductId(detailDO.getProductId());
            respVO.setFinishNumber(recordPlanService.selectSumBy(planId, itemId));
            return respVO;
        }
        return null;
    }

    @Override
    public List<ItemRequisitionDetailRespVO> getItemRequisitionList(Long planId) {
        ItemRequisitionDO itemRequisitionDO = itemRequisitionMapper.selectByPlanId(planId);
        List<ItemRequisitionDetailRespVO> respVOList = new ArrayList<>();
        if (itemRequisitionDO != null) {
            List<ItemRequisitionDetailDO> detailDOList =
                    itemRequisitionDetailMapper.selectListByItemRequisitionId(itemRequisitionDO.getId());
            for (ItemRequisitionDetailDO detailDO : detailDOList) {
                ItemRequisitionDetailRespVO respVO = new ItemRequisitionDetailRespVO()
                        .setItemRequisitionId(itemRequisitionDO.getId())
                        .setUnitId(detailDO.getUnitId())
                        .setNumber(detailDO.getNumber())
                        .setProductId(detailDO.getProductId());
                respVO.setFinishNumber(recordPlanService.selectSumBy(planId, detailDO.getProductId()));
                respVOList.add(respVO);
            }
        }
        return respVOList;
    }
}