package com.rongwei.bscommon.sys.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwei.bscommon.sys.dao.*;
import com.rongwei.bscommon.sys.service.ApsProductionOrderService;
import com.rongwei.bscommon.sys.utils.ApsUtils;
import com.rongwei.bsentity.domain.ApsBlankOrderDo;
import com.rongwei.bsentity.domain.ApsProductionMergeOrderDo;
import com.rongwei.bsentity.domain.ApsProductionOrderDo;
import com.rongwei.bsentity.vo.ApsProductDetailVo;
import com.rongwei.bsentity.vo.CheckAndSaveOrUpdateOrderReq;
import com.rongwei.bsentity.vo.ProductDetailIdAndPlanOutPutRollCountAllVo;
import com.rongwei.bsentity.vo.ProductTypeIdAndPidVo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.vo.MailDo;
import com.rongwei.safecommon.fegin.CXCommonFeginClient;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.safecommon.utils.SaveConstans;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.ORDEROUTTIME_AUDIT_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyTitle.ORDEROUTTIMEAUDIT_TITLE;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.ORDEROUTTIME_AUDIT;

/**
 *
 */
@Service
public class ApsProductionOrderServiceImpl extends ServiceImpl<ApsProductionOrderDao, ApsProductionOrderDo>
        implements ApsProductionOrderService {
    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private ApsProcessOperationDao apsProcessOperationDao;
    @Autowired
    private ApsBlankOrderDao apsBlankOrderDao;
    @Autowired
    private ApsProductDetailDao apsProductDetailDao;
    @Autowired
    private ApsProcessOperationProcessEquDao apsProcessOperationProcessEquDao;
    @Autowired
    private ApsProcessOperationBackupDao apsProcessOperationBackupDao;
    @Autowired
    private ApsProcessOperationProcessEquBackupDao apsProcessOperationProcessEquBackupDao;
    @Autowired
    private CXCommonFeginClient autoCommonFeginClient;

    public static final String ERROR_MSG = "%s上诉订单的排程交货期大于承诺交货期";

    /**
     * 发布订单排程
     *
     * @param productionOrderIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R publish(List<String> productionOrderIds) {
        if (productionOrderIds.isEmpty()) {
            return R.ok();
        }
        // 如果 订单排程交货期>承诺交货期 抛出异常信息
        List<ApsProductionOrderDo> list = this.list(new LambdaQueryWrapper<ApsProductionOrderDo>()
                .in(ApsProductionOrderDo::getId, productionOrderIds)
                .apply(" SCHEDULEDELIVERYDATE>PROMISEDELIVERYDATE"));
        if (!list.isEmpty()) {
            String collect = list.stream()
                    .map(info -> info.getOrderno() + "-" + info.getCustomname())
                    .collect(Collectors.joining(";"));
            log.error("存在排程交货期大于承诺交货期 的订单：{}", collect);
            return R.error(String.format(ERROR_MSG, collect));
        }

        // 更新工序作业的生产状态和是否锁定=是
        apsProcessOperationDao.publish(productionOrderIds);

        apsProcessOperationProcessEquDao.publish(productionOrderIds);
        // 更新坯料计划的生产状态
        apsBlankOrderDao.publish(productionOrderIds);
        // 更新产品明细的生产状态
        apsProductDetailDao.publish(productionOrderIds);
        // 更新订单的生产状态
        this.baseMapper.publish(productionOrderIds);
        // 根据坯料ID 删除 备份数据
        List<ApsBlankOrderDo> apsBlankOrderDos = apsBlankOrderDao.selectList(new LambdaQueryWrapper<ApsBlankOrderDo>()
                .in(ApsBlankOrderDo::getProductionorderid, productionOrderIds));
        ApsUtils.clearBackup(null);
        return R.ok();
    }

    /**
     * 取消发布订单排程
     *
     * @param productionOrderIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R publishCancel(List<String> productionOrderIds) {
        // 更新工序作业的生产状态和是否锁定=是
        apsProcessOperationDao.publishCancel(productionOrderIds);
        apsProcessOperationProcessEquDao.publishCancel(productionOrderIds);
        // 更新坯料计划的生产状态
        apsBlankOrderDao.publishCancel(productionOrderIds);
        // 更新产品明细的生产状态
        apsProductDetailDao.publish(productionOrderIds);
        // 更新订单的生产状态
        this.baseMapper.publishCancel(productionOrderIds);
        List<ApsBlankOrderDo> apsBlankOrderDos = apsBlankOrderDao.selectList(new LambdaQueryWrapper<ApsBlankOrderDo>()
                .in(ApsBlankOrderDo::getProductionorderid, productionOrderIds));
        List<String> blankIds = apsBlankOrderDos.stream().map(ApsBlankOrderDo::getId).collect(Collectors.toList());
        // 根据坯料ID 删除 备份数据
        ApsUtils.clearBackup(null);
        return R.ok();
    }

    @Override
    @Transactional
    public R checkAndSaveOrUpdateOrder(CheckAndSaveOrUpdateOrderReq req) {
        //订单信息
        ApsProductionOrderDo apsProductionOrderDo = req.getApsProductionOrderDo();
        //合并订单信息
        List<ApsProductionMergeOrderDo> apsProductionMergeOrderDoList = req.getApsProductionMergeOrderDoList();
        //产品明细信息
        List<ApsProductDetailVo> apsProductDetailVoList = req.getApsProductDetailVoList();
        //坯料计划信息(坯料计划是一保存的状态，校验直接通过数据库查询)
        List<ApsBlankOrderDo> apsBlankOrderDoList = apsBlankOrderDao.selectList(new QueryWrapper<ApsBlankOrderDo>().lambda().eq(ApsBlankOrderDo::getProductionorderid, apsProductionOrderDo.getId()));
        //是否需要检验坯料计划是否已排程
        Boolean checkSchedule = req.getCheckSchedule();

        //=========检查坯料计划的个数和状态=============
        if (ObjectUtil.isEmpty(apsBlankOrderDoList)) {
            return R.error("坯料计划至少有一个");
        }
        for (int i = 0; i < apsBlankOrderDoList.size(); i++) {
            if (apsBlankOrderDoList.get(i).getIsstag().equals("是")) {
                return R.error("第" + (i + 1) + "个坯料计划为暂存数据，请先保存再提交");
            }
        }

        //提交时需要校验是否已排程
        if (checkSchedule) {
            //如果坯料计划生产状态=待排程；错误提示：坯料计划 {输入物料描述} 还未排程
            for (ApsBlankOrderDo apsBlankOrderDo : apsBlankOrderDoList) {
                if (ObjectUtil.isNotEmpty(apsBlankOrderDo.getProductstatus()) && apsBlankOrderDo.getProductstatus().equals(SaveConstans.ProductionStatus.TO_BE_SCHEDULED)) {
                    return R.error("坯料计划 " + apsBlankOrderDo.getInputreportdescribe() + " 还未排程");
                }
            }
        }

        //============校验承诺交期============
        //如果承诺交货期为空，错误提示：请填写订单{订单号}{客户简称}的承诺交货期
        if (ObjectUtil.isEmpty(apsProductionOrderDo.getPromisedeliverydate())) {
            return R.error("请填写订单" + apsProductionOrderDo.getOrderno() + apsProductionOrderDo.getCustomname() + "的承诺交货期");
        }
        //如果承诺交货期<排程交货期，错误提示：承诺交货期不能早于排程交货期{排程交货期}
        if (apsProductionOrderDo.getPromisedeliverydate().compareTo(apsProductionOrderDo.getScheduledeliverydate()) < 0) {
            return R.error("承诺交货期不能早于排程交货期" + DateUtil.format(apsProductionOrderDo.getScheduledeliverydate(), "yyyy-MM-dd"));
        }

        //============校验计划输出订单总重量==============
        //检查每个订单产品，如果该订单产品坯料计划输出总重量 不等于 该订单产品订单总数量；
        //错误提示：订单产品 {输入物料描述} 订单总数量与坯料计划输出总重量不一致
        if (ObjectUtil.isEmpty(apsProductDetailVoList) || apsProductDetailVoList.size() <= 0) {
            return R.error("产品明细至少有一个");
        }
        for (ApsProductDetailVo apsProductDetailVo : apsProductDetailVoList) {
            if (apsProductDetailVo.getTotalordercount().compareTo(apsProductDetailVo.getPlanout()) != 0) {
                return R.error("订单产品 " + apsProductDetailVo.getInputmaterialdescription() + " 订单总数量与坯料计划输出总重量不一致");
            }
        }

        //查询此订单所有产品明细对应的输出成品的卷数和
        List<ProductDetailIdAndPlanOutPutRollCountAllVo> planOutPutRollCountAllVos = this.baseMapper.getProductDetailIdAndPlanOutPutRollCountAll(apsProductDetailVoList.get(0).getMainid());
        //检查每个订单产品，如果该订单产品填写了卷数，
        //并且该订单产品对应坯料输出成品的计划输出订单卷数合计不等于订单产品的卷数，
        //错误提示：订单产品 {输入物料描述} 的卷数与坯料计划的计划输出订单卷数不一致
        for (ApsProductDetailVo apsProductDetailVo : apsProductDetailVoList) {
            if (ObjectUtil.isNotEmpty(apsProductDetailVo.getRollnum())) {
                for (ProductDetailIdAndPlanOutPutRollCountAllVo planOutPutRollCountAllVo : planOutPutRollCountAllVos) {
                    if (planOutPutRollCountAllVo.getProductDetailId().equals(apsProductDetailVo.getId())) {
                        if (planOutPutRollCountAllVo.getPlanOutPutRollCountAll().equals(apsProductDetailVo.getRollnum())) {
                            break;
                        } else {
                            return R.error("订单产品 " + apsProductDetailVo.getInputmaterialdescription() + " 的卷数与坯料计划的计划输出订单卷数不一致");
                        }
                    }
                }
            }
        }

        //===============校验产品明细的长===================
        if (ObjectUtil.isEmpty(apsProductDetailVoList)) {
            return R.error("产品明细至少有一个");
        }

        //获取产品明细的所有产品类型ID（去重）
        Set<String> productTypeIds = apsProductDetailVoList.stream().map(ApsProductDetailVo::getProducttypeid).collect(Collectors.toSet());
        String join = String.join("','", productTypeIds);

        List<ProductTypeIdAndPidVo> productTypeIdAndPidList = this.baseMapper.selectProductTypeIdAndPid(join);
        if (ObjectUtil.isNotEmpty(productTypeIdAndPidList)) {
            for (ProductTypeIdAndPidVo productTypeIdAndPidVo : productTypeIdAndPidList) {
                for (int i = 0; i < apsProductDetailVoList.size(); i++) {
                    ApsProductDetailVo apsProductDetailVo = apsProductDetailVoList.get(i);
                    if (apsProductDetailVo.getProducttypeid().equals(productTypeIdAndPidVo.getId())) {
                        //如果是铝板或铝锭
                        if (productTypeIdAndPidVo.getPid().equals(SaveConstans.ProductionType.LVBAN_ID) || productTypeIdAndPidVo.getPid().equals(SaveConstans.ProductionType.BANDING_ID)) {
                            //判断长度是否为空
                            if (ObjectUtil.isEmpty(apsProductDetailVo.getProlength())) {
                                return R.error("第" + (i + 1) + "个产品明细，产品类型是铝板或板锭时长度必填");
                            }
                        }
                    }
                }
            }
        }

        //================循环校验坯料计划===============


        return null;
    }

    /*
    订单未及时评审提醒
     */
    @Override
    public void orderOuttimeAudit() {
        log.info("订单未及时评审提醒开始");
        List<ApsProductionOrderDo> apsProductionOrderDos = this.baseMapper.getOrderOuttimeAudit();
        for (ApsProductionOrderDo apsProductionOrderDo : apsProductionOrderDos) {
            //系统通知（移动端和PC端个人工作台）
            CXCommonUtils.sendNotify(ORDEROUTTIMEAUDIT_TITLE, String.format(ORDEROUTTIME_AUDIT_CONTENT, apsProductionOrderDo.getOrderno()), null, Arrays.asList(apsProductionOrderDo.getCreateuserid().split(",")), apsProductionOrderDo.getId(), ORDEROUTTIME_AUDIT, false);

            //邮件提醒
            MailDo mailDo = new MailDo();
            mailDo.setReceiveEmail(apsProductionOrderDo.getModifyusername().split(","));
            mailDo.setNeedTransReceive(false);
            mailDo.setCcEmail(new String[]{});
            mailDo.setSubject(ORDEROUTTIMEAUDIT_TITLE);
            mailDo.setContent(String.format(ORDEROUTTIME_AUDIT_CONTENT, apsProductionOrderDo.getOrderno()));
            autoCommonFeginClient.sendHtmlMail(mailDo);
        }
    }

}




