package com.xisc.pm.app.service.impl;

import com.google.common.collect.Maps;
import com.xisc.boot.common.feign.pojo.MtUserInfo;
import com.xisc.boot.common.sys.UserClient;
import com.xisc.pm.api.dto.PmPdEventResDTO;
import com.xisc.pm.api.dto.PmPdRecDTO;
import com.xisc.pm.api.dto.PmPdRecRequestDTO;
import com.xisc.pm.app.service.PmPdRecService;
import com.xisc.pm.app.service.strategy.PdEventStrategyFactory;
import com.xisc.pm.app.service.strategy.pdevent.PdEventStrategy;
import com.xisc.pm.domain.entity.PmContMscTech;
import com.xisc.pm.domain.entity.PmPdRec;
import com.xisc.pm.domain.entity.PmPdRecCfg;
import com.xisc.pm.domain.entity.PmProCont;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.repository.PmContMscTechRepository;
import com.xisc.pm.domain.repository.PmPdRecCfgRepository;
import com.xisc.pm.domain.repository.PmPdRecRepository;
import com.xisc.pm.domain.repository.PmProContProdTtrRepository;
import com.xisc.pm.domain.repository.PmProContRepository;
import com.xisc.pm.infra.enums.PdEventType;
import com.xisc.pm.infra.util.BeanUtils;
import io.choerodon.core.domain.Page;
import io.choerodon.core.exception.CommonException;
import io.choerodon.core.oauth.CustomUserDetails;
import io.choerodon.core.oauth.DetailsHelper;
import io.choerodon.mybatis.pagehelper.PageHelper;
import io.choerodon.mybatis.pagehelper.domain.PageRequest;
import org.apache.commons.lang3.StringUtils;
import org.hzero.core.base.BaseConstants;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.helper.SecurityTokenHelper;
import org.hzero.mybatis.util.Sqls;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 组板履历表应用服务默认实现
 *
 * @author 曾俊 jun.zeng@hand-china.com 2024-07-31 08:01:11
 */
@Service
public class PmPdRecServiceImpl implements PmPdRecService {

    private final PmPdRecRepository pmPdRecRepository;
    
    @Autowired
    private PmContMscTechRepository pmContMscTechRepository ;
    
    @Autowired
    private PmProContRepository pmProContRepository;
    
    @Autowired
    private PmPdRecCfgRepository pmPdRecCfgRepository;
    
    @Autowired
    private PmProContProdTtrRepository pmProContProdTtrRepository;
    
    @Autowired
    private UserClient userClient;

    @Autowired
    public PmPdRecServiceImpl(PmPdRecRepository pmPdRecRepository) {
        this.pmPdRecRepository = pmPdRecRepository;
    }

    @Override
    public Page<PmPdRec> list(Long tenantId, PmPdRecRequestDTO pmPdRec, PageRequest pageRequest) {
//        Date createDateFrom = null;
//        Date createDateTo = null;
//        try {
//            if(StringUtils.isNotBlank(pmPdRec.getCreationDateFrom())) {
//                String dateStr = pmPdRec.getCreationDateFrom() + " 00:00:00";
//                createDateFrom = DateUtils.parseDate(dateStr, BaseConstants.Pattern.DATETIME);
//            }
//            if(StringUtils.isNotBlank(pmPdRec.getCreationDateTo())) {
//                String dateStr = pmPdRec.getCreationDateTo() + " 23:59:59";
//                createDateTo = DateUtils.parseDate(dateStr, BaseConstants.Pattern.DATETIME);
//            }
//        } catch (ParseException e) {
//            throw new CommonException("pm.pm.pm_pd_rec_001") ;
//        }
        Condition condition = Condition.builder(PmPdRec.class)
                .andWhere(Sqls.custom()
                        .andLike(PmPdRec.FIELD_ORDER_NO, pmPdRec.getOrderNo(), true)
                        .andLike(PmPdRec.FIELD_EVENT_MAKER, pmPdRec.getEventMaker(), true)
                        .andEqualTo(PmPdRec.FIELD_TRACK_SEQ_NO , pmPdRec.getTrackSeqNo(), true)
                        .andGreaterThanOrEqualTo(PmPdRec.FIELD_CREATION_DATE, pmPdRec.getCreationDateFrom(), true)
                        .andLessThanOrEqualTo(PmPdRec.FIELD_CREATION_DATE, pmPdRec.getCreationDateTo(), true))
                .build();
        Page<PmPdRec> pdRecs = PageHelper.doPageAndSort(pageRequest, () -> this.pmPdRecRepository.selectByCondition(condition));
        List<Long> userId = new ArrayList<>();
        for (PmPdRec record : pdRecs) {
            if (StringUtils.isNotEmpty(record.getEventMaker()) && record.getEventMaker().matches("\\d+")) {
                userId.add(Long.valueOf(record.getEventMaker()));
            }
            userId.add(record.getCreatedBy());
            userId.add(record.getLastUpdatedBy());
        }
        Map<Long, MtUserInfo> userIdMap = userClient.userInfoBatchGet(tenantId, userId);
        for (PmPdRec record : pdRecs) {
            if (StringUtils.isNotEmpty(record.getEventMaker()) && record.getEventMaker().matches("\\d+")) {
                MtUserInfo mtUserInfo = userIdMap.get(Long.valueOf(record.getEventMaker()));
                if(mtUserInfo != null) {
                    record.setEventMakerName(mtUserInfo.getLoginName() + mtUserInfo.getRealName());
                }
            }
            MtUserInfo createInfo = userIdMap.get(record.getCreatedBy());
            if(createInfo != null) {
                record.setCreatedByName(createInfo.getLoginName() + createInfo.getRealName());
            }
            MtUserInfo updateInfo = userIdMap.get(record.getLastUpdatedBy());
            if(updateInfo != null) {
                record.setLastUpdatedByName(updateInfo.getLoginName() + updateInfo.getRealName());
            }
        }
        return pdRecs;
    }

    @Override
    public PmPdRec detail(Long tenantId, Long pprId) {
        return pmPdRecRepository.selectByPrimaryKey(pprId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PmPdRec createEvent(Long tenantId, PmPdRecDTO pmPdRecDTO) {
        if(StringUtils.isBlank(pmPdRecDTO.getEventCode())) {
            throw new CommonException("pm.pm_pd_rec_003", "事件标识");
        }
        // 获取事件类型
        PdEventType pdEventType = PdEventType.getByCode(pmPdRecDTO.getEventCode());
        if(pdEventType.isCreateEventRec()) {
            PmPdRecCfg pmPdRecCfg = pmPdRecCfgRepository.selectByEventCode(pdEventType.getCode());
            // 通过履历配置表，校验字段完整性
            checkByPmPdRecCfg(pmPdRecDTO, pmPdRecCfg);
        }
        // 
        PmContMscTech pmContMscTech = null;
        PmProCont pmProCont = null;
        // 合同属性 和 合同表主键是一致的，这里直接用合同表主键查询即可
        PmProContProdTtr pmProContProdTtr = null;
        
        PmPdRec pmPdRec = new PmPdRec();
        BeanCopier.create(PmPdRecDTO.class, PmPdRec.class, false).copy(pmPdRecDTO, pmPdRec, null);
        pmPdRec.setTrackSeqNo(String.valueOf(System.currentTimeMillis()));
        
        if(StringUtils.isNotBlank(pmPdRecDTO.getOrderNo())) {
            if (StringUtils.isNotEmpty(pmPdRecDTO.getMscLineNo())) {
                // 获取全程工序代码，如果没有会抛出异常
                pmContMscTech = pmContMscTechRepository.selectWholeBacklog(pmPdRecDTO.getOrderNo() , pmPdRecDTO.getMscLineNo());
                if(null == pmContMscTech) {
                    throw new CommonException("pm.pm_cont_msc_tech_001", pmPdRecDTO.getOrderNo() , pmPdRecDTO.getMscLineNo());
                }
            }
            // 获取生产合同
            pmProCont = pmProContRepository.queryByOrderNo(pmPdRecDTO.getOrderNo() ,tenantId);
            if (null == pmProCont) {
                // 订单编号不存在
                throw new CommonException("pm.pm_pro_cont_002");
            }
            // 合同属性 和 合同表主键是一致的，这里直接用合同表主键查询即可
            pmProContProdTtr = pmProContProdTtrRepository.selectByPrimaryKey(pmProCont.getProContId());
            if(pmPdRec.getQty() != null) {
                pmPdRec.setWt(pmProContProdTtr.getOrderUnitAimWt().multiply(pmPdRec.getQty()));
            }
            if (Objects.nonNull(pmContMscTech)) {
                pmPdRec.setWholeBacklog(pmContMscTech.getWholeBacklog());
                pmPdRec.setWholeBacklogCode(pmContMscTech.getWholeBacklogCode());
            }
        }
        pmPdRec.setTenantId(tenantId);
        // 获取事件策略
        PdEventStrategy eventStrategy = PdEventStrategyFactory.matchPdEventStrategy(pdEventType);
        if(null != eventStrategy) {
            // 如果存在事件处理策略，处理事件
            PmPdEventResDTO pdEventRes = eventStrategy.handleEvent(pmPdRec , pmContMscTech , pmProCont , pmProContProdTtr);
            if(pdEventRes.getContMscTech() != null) {
                this.pmContMscTechRepository.updateByPrimaryKey(pdEventRes.getContMscTech());
            }
            if(pdEventRes.getProConts() != null) {
                this.pmProContRepository.updateByPrimaryKey(pdEventRes.getProConts());
            }
            if(pdEventRes.getContProdTtr() != null) {
                this.pmProContProdTtrRepository.updateByPrimaryKey(pdEventRes.getContProdTtr());
            }
        }
        if(pdEventType.isCreateEventRec()) {
            pmPdRecRepository.insertSelective(pmPdRec);
        }
        return pmPdRec;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PmPdRec> createEvent(Long tenantId, List<PmPdRecDTO> pmPdRecDTOList , PdEventType pdEventType , String systemCode , String apiCode) {
        if(pmPdRecDTOList == null || pmPdRecDTOList.isEmpty()) {
            return new ArrayList<>();
        }
        // 获取事件类型
        PmPdRecCfg pmPdRecCfg = null;
        if(pdEventType.isCreateEventRec()) {        
            pmPdRecCfg = pmPdRecCfgRepository.selectByEventCode(pdEventType.getCode());
        }
        String trackSeqNo = String.valueOf(System.currentTimeMillis());
        List<String> orderNoList = new ArrayList<>();
        String mscLineNo = null;
        List<PmPdRec> pmPdRecs = new ArrayList<>(pmPdRecDTOList.size());
        CustomUserDetails userDetails = DetailsHelper.getUserDetails();
        for (PmPdRecDTO pmPdRecDTO : pmPdRecDTOList) {
            // 通过履历配置表，校验字段完整性
            pmPdRecDTO.setEventCode(pdEventType.getCode());
            pmPdRecDTO.setSystemCode(systemCode);
            pmPdRecDTO.setApiCode(apiCode);
            if(StringUtils.isBlank(pmPdRecDTO.getEventMaker())) {
                pmPdRecDTO.setEventMaker(userDetails.getUserId().toString());
            }
            if(pdEventType.isCreateEventRec()) {  
                checkByPmPdRecCfg(pmPdRecDTO, pmPdRecCfg);
            }
            orderNoList.add(pmPdRecDTO.getOrderNo());
            mscLineNo = pmPdRecDTO.getMscLineNo();
            PmPdRec pdRec = BeanUtils.copy(pmPdRecDTO, PmPdRec.class);
            pdRec.setTenantId(tenantId);
            pdRec.setTrackSeqNo(trackSeqNo);
            // 调用模块简称
            pdRec.setAttribute1(pmPdRecDTO.getModuleCode());
            pmPdRecs.add(pdRec);
        }
        // 获取事件策略
        PdEventStrategy eventStrategy = PdEventStrategyFactory.matchPdEventStrategy(pdEventType);
        
        List<PmProCont> updatePmProConts = new ArrayList<>();
        List<PmProContProdTtr> updatePmProContProdTtrs = new ArrayList<>();
        List<PmContMscTech> updatePmContMscTechs = new ArrayList<>();
        
        if(null != eventStrategy) {
            Map<String , PmContMscTech> pmContMscTechMap = Maps.newHashMap();
            List<PmProCont> pmProConts = pmProContRepository.queryByOrderNoList(orderNoList, tenantId);
            List<PmProContProdTtr> pmProContProdTtrs = pmProContProdTtrRepository.selectByOrderNoList(orderNoList, tenantId);
            Map<String , PmProCont> pmProContMap = Maps.uniqueIndex(pmProConts, PmProCont::getOrderNo);
            Map<String , PmProContProdTtr> pmProContProdTtrMap = Maps.uniqueIndex(pmProContProdTtrs, PmProContProdTtr::getOrderNo);
            if(StringUtils.isNotBlank(mscLineNo)) {
                List<PmContMscTech> pmContMscTechs = pmContMscTechRepository.selectByOrderNoAndMscLineNo(orderNoList, mscLineNo, tenantId);
                pmContMscTechMap = Maps.uniqueIndex(pmContMscTechs, PmContMscTech::getOrderNo);
            }
            
            for (PmPdRec pmPdRec : pmPdRecs) {
                PmContMscTech pmContMscTech = pmContMscTechMap.get(pmPdRec.getOrderNo());
                if(null != pmContMscTech) {
//                    throw new CommonException("pm.pm_cont_msc_tech_001", pmPdRec.getOrderNo() , pmPdRec.getMscLineNo());
                    pmPdRec.setWholeBacklog(pmContMscTech.getWholeBacklog());
                    pmPdRec.setWholeBacklogCode(pmContMscTech.getWholeBacklogCode());
                }
                PmProCont pmProCont = pmProContMap.get(pmPdRec.getOrderNo());
                if (null == pmProCont) {
                    // 订单编号不存在
                    throw new CommonException("pm.pm_pro_cont_002");
                }
                PmProContProdTtr pmProContProdTtr = pmProContProdTtrMap.get(pmPdRec.getOrderNo());
                
                if(pmPdRec.getQty() != null) {
                    pmPdRec.setWt(pmProContProdTtr.getOrderUnitAimWt().multiply(pmPdRec.getQty()));
                }
                PmPdEventResDTO pmPdEventResDTO = eventStrategy.handleEvent(pmPdRec, pmContMscTech, pmProCont, pmProContProdTtr);
                if(pmPdEventResDTO.getContMscTech() != null && pmContMscTech != null) {
                    updatePmContMscTechs.add(pmPdEventResDTO.getContMscTech());
                    pmContMscTech.setObjectVersionNumber(pmContMscTech.getObjectVersionNumber() + 1L);
                }
                if(pmPdEventResDTO.getProConts() != null) {
                    updatePmProConts.add(pmPdEventResDTO.getProConts());
                    pmProCont.setObjectVersionNumber(pmProCont.getObjectVersionNumber() + 1L);
                }
                if(pmPdEventResDTO.getContProdTtr() != null) {
                    updatePmProContProdTtrs.add(pmPdEventResDTO.getContProdTtr());
                    pmProContProdTtr.setObjectVersionNumber(pmProContProdTtr.getObjectVersionNumber() + 1L);
                }
            }
        }
        if(updatePmContMscTechs != null || !updatePmContMscTechs.isEmpty()) {
            pmContMscTechRepository.batchUpdateByPrimaryKeySelective(updatePmContMscTechs);
        }
        if(updatePmProContProdTtrs != null || !updatePmProContProdTtrs.isEmpty()) {
            pmProContProdTtrRepository.batchUpdateByPrimaryKeySelective(updatePmProContProdTtrs);
        }
        if(updatePmProConts != null || !updatePmProConts.isEmpty()) {
            pmProContRepository.batchUpdateByPrimaryKeySelective(updatePmProConts);
        }
        if(pdEventType.isCreateEventRec()) {  
            pmPdRecRepository.batchInsertSelective(pmPdRecs);
        }
        return pmPdRecs;
    }

    /**
     * 
     * @param pmPdRecDTO 履历事件参数
     * @param pmPdRecCfg 履历配置表信息
     */
    private void checkByPmPdRecCfg(PmPdRecDTO pmPdRecDTO , PmPdRecCfg pmPdRecCfg) {
        if(pmPdRecCfg == null || pmPdRecCfg.getLogFlag() == null 
                || !(BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getLogFlag().longValue())) {
            // 组板履历事件配置表无该事件【event_code】
            throw new CommonException("pm.pm_pd_rec_cfg_002", pmPdRecDTO.getEventCode());
        }
        if(StringUtils.isBlank(pmPdRecDTO.getSystemCode())) {
            throw new CommonException("pm.pm_pd_rec_003", "系统标识");
        }
        if(StringUtils.isBlank(pmPdRecDTO.getApiCode())) {
            throw new CommonException("pm.pm_pd_rec_003", "功能标识");
        }
        if(StringUtils.isBlank(pmPdRecDTO.getEventMaker())) {
            throw new CommonException("pm.pm_pd_rec_003", "事件员工编号");
        }
        if(pmPdRecCfg.getOrderNoFlag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getOrderNoFlag().longValue()) {
            if(StringUtils.isBlank(pmPdRecDTO.getOrderNo())) {
                // 事件配置表中orderNoFlag 为1 合同号必填
                throw new CommonException("pm.pm_pd_rec_003", "合同号");
            }
        }
        if(pmPdRecCfg.getMatNoFlag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getMatNoFlag().longValue()) {
            if(StringUtils.isBlank(pmPdRecDTO.getMatNo())) {
                throw new CommonException("pm.pm_pd_rec_003", "材料号");
            }
        }
        if(pmPdRecCfg.getWtFlagFlag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getWtFlagFlag().longValue()) {
            if(pmPdRecDTO.getQty() == null || pmPdRecDTO.getQty().compareTo(BigDecimal.ZERO) <= 0) {
                // 重量不能为0，重量与件数保持一致，这里校验件数效果一致。
                throw new CommonException("pm.pm_pd_rec_004", "重量");
            }
        }
        if(pmPdRecCfg.getQtyFlagFlag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getQtyFlagFlag().longValue()) {
            if(pmPdRecDTO.getQty() == null || pmPdRecDTO.getQty().compareTo(BigDecimal.ZERO) <= 0) {
                // 重量不能为0
                throw new CommonException("pm.pm_pd_rec_004", "件数");
            }
        }
        if(pmPdRecCfg.getKeyvalue1Flag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getKeyvalue1Flag().longValue()) {
            if(StringUtils.isBlank(pmPdRecDTO.getKeyvalue1())) {
                throw new CommonException("pm.pm_pd_rec_003", "关键字串1");
            }
        }
        if(pmPdRecCfg.getKeyvalue2Flag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getKeyvalue2Flag().longValue()) {
            if(StringUtils.isBlank(pmPdRecDTO.getKeyvalue2())) {
                throw new CommonException("pm.pm_pd_rec_003", "关键字串2");
            }
        }
        if(pmPdRecCfg.getKeyvalue3Flag() != null && BaseConstants.Flag.YES.longValue() == pmPdRecCfg.getKeyvalue3Flag().longValue()) {
            if(StringUtils.isBlank(pmPdRecDTO.getKeyvalue3())) {
                throw new CommonException("pm.pm_pd_rec_003", "关键字串3");
            }
        }
        
    }
    
    

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PmPdRec update(Long tenantId, PmPdRec pmPdRec) {
        SecurityTokenHelper.validToken(pmPdRec);
        pmPdRecRepository.updateByPrimaryKeySelective(pmPdRec);
        return pmPdRec;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(PmPdRec pmPdRec) {
        SecurityTokenHelper.validToken(pmPdRec);
        pmPdRecRepository.deleteByPrimaryKey(pmPdRec);
    }
}
