package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesProdOrgExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionRecordService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesProduceSn;
import cn.estsh.i3plus.pojo.mes.bean.MesProductionRecord;
import cn.estsh.i3plus.pojo.mes.repository.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.util.ResultBean;
import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description :
 * @Reference :
 * @Author : Castle
 * @CreateDate : 2024/6/20 21:20
 * @Modify:
 **/
@Service
public class MesProductionRecordService implements IMesProductionRecordService {

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private IMesProdOrgExtService prodOrgExtService;

    @Autowired
    private MesTimeEfficientCfgRepository timeEfficientCfgRepository;

    @Autowired
    private MesProductionRecordRepository productionRecordRepository;

    @Autowired
    private MesProductionAssemblyRepository productionAssemblyRepository;

    @Autowired
    private MesCraftRepository mesCraftRepository;

    @Autowired
    private MesProduceSnRepository mesProduceSnRepository;

    @Autowired
    private MesWorkCenterRepository mesWorkCenterRepository;

    @Autowired
    private MesWorkCellRepository mesWorkCellRepository;

    @Autowired
    private MesProductionRecordRepository productionRecordRao;

    @Override
    public List<MesProductionRecord> findProductionRecordList(String organizeCode, String productSn) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn)) return null;
        return productionRecordRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn});
    }

    @Override
    public Integer findFrontProcessProductionRecord(String organizeCode, String productSn, String craftCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn) || StringUtils.isEmpty(craftCode)) return null;
        return productionRecordRepository.findByPropertyCount(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN, MesPcnExtConstWords.CRAFT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn, craftCode});
    }

    //查询加工记录, 根据完成时间倒序
    @Override
    public List<MesProductionRecord> findProductionRecordListCompleteDateTimeDesc(String organizeCode, String productSn) {
        List<MesProductionRecord> productionRecordList = findProductionRecordList(organizeCode, productSn);
        if (CollectionUtils.isEmpty(productionRecordList)) return productionRecordList;
        return productionRecordList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesProductionRecord::getCompleteDateTime).reversed()).collect(Collectors.toList());
    }

    @Override
    public List<MesProductionRecord> findProductionRecordList(String organizeCode, String productSn, String partNo) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn) || StringUtils.isEmpty(partNo)) return null;
        return productionRecordRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN, MesPcnExtConstWords.PART_NO},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn, partNo});
    }

    @Override
    public List<MesProductionRecord> findProductionRecordList(String organizeCode, String productSn, String partNo, String processCode, String craftCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn) || StringUtils.isEmpty(partNo) || StringUtils.isEmpty(processCode) || StringUtils.isEmpty(craftCode)) return null;
        return productionRecordRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN, MesPcnExtConstWords.PART_NO, MesPcnExtConstWords.PROCESS_CODE, MesPcnExtConstWords.CRAFT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn, partNo, processCode, craftCode});
    }

    @Override
    public List<MesProductionRecord> findProductionRecordListByCraft(String organizeCode, String productSn, String craftCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn) || StringUtils.isEmpty(craftCode)) return null;
        return productionRecordRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN, MesPcnExtConstWords.CRAFT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn, craftCode});
    }

    @Override
    public List<MesProductionRecord> findProductionRecordList(String organizeCode, List<String> orderNoList, Integer reportStatus) {
        if(StringUtils.isEmpty(orderNoList) || CollectionUtils.isEmpty(orderNoList) || Objects.isNull(reportStatus)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        if(orderNoList.size() == MesPcnExtConstWords.ONE) {
            DdlPreparedPack.getStringEqualPack(orderNoList.iterator().next(),MesPcnExtConstWords.WORK_ORDER_NO,packBean);
        } else{
            DdlPreparedPack.getInPackList(orderNoList,MesPcnExtConstWords.WORK_ORDER_NO,packBean);
        }
        DdlPreparedPack.getNumEqualPack(reportStatus,MesPcnExtConstWords.REPORT_TYPE,packBean);
        return productionRecordRepository.findByHqlWhere(packBean);
    }

    @Override
    public void updateProductionRecord(String organizeCode, String userName, String sn) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(sn, "productSn", ddlPackBean);
        productionRecordRepository.updateByProperties(new String[]{"modifyUser", "modifyDatetime","reportStatus"},
                new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_20.getValue() },ddlPackBean);
    }
    @Override
    public void updateProductionRecord(String organizeCode, String userName, Long id, String errorMsg) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(id, "id", ddlPackBean);

        MesProductionRecord mesProductionRecord = productionRecordRepository.getByProperty(ddlPackBean);
        if (mesProductionRecord !=null && Objects.equals(mesProductionRecord.getReportStatus(), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue())) {
            productionRecordRepository.updateByPropertiesNoSync(new String[]{"modifyUser", "modifyDatetime","reportStatus", "remark"},
                    new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue(), errorMsg },ddlPackBean);
        } else {
            productionRecordRepository.updateByProperties(new String[]{"modifyUser", "modifyDatetime","reportStatus", "remark"},
                    new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue(), errorMsg },ddlPackBean);

        }
    }

    @Override
    public void updateProductionRecordList(String organizeCode, String userName, List<Long> ids, String errorMsg) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(ids, "id", ddlPackBean);

        List<MesProductionRecord> mesProductionRecordList = productionRecordRepository.findByHqlWhere(ddlPackBean);

        List<Long> failList = new ArrayList<>();
        List<Long> noFailList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(mesProductionRecordList)) {
            failList = mesProductionRecordList.stream().filter(mesProductionRecord -> Objects.equals(mesProductionRecord.getReportStatus(), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue())).map(MesProductionRecord::getId).collect(Collectors.toList());
            noFailList = mesProductionRecordList.stream().filter(mesProductionRecord -> !Objects.equals(mesProductionRecord.getReportStatus(), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue())).map(MesProductionRecord::getId).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(failList)) {
                DdlPackBean failPackBean = DdlPackBean.getDdlPackBean(organizeCode);
                DdlPreparedPack.getInPackList(failList, "id", failPackBean);

                productionRecordRepository.updateByPropertiesNoSync(new String[]{"modifyUser", "modifyDatetime", "reportStatus", "remark"},
                        new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue(), errorMsg}, failPackBean);
            }
            if (!CollectionUtils.isEmpty(noFailList)) {
                DdlPackBean nofailPackBean = DdlPackBean.getDdlPackBean(organizeCode);
                DdlPreparedPack.getInPackList(noFailList, "id", nofailPackBean);

                productionRecordRepository.updateByProperties(new String[]{"modifyUser", "modifyDatetime","reportStatus", "remark"},
                        new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue(), errorMsg }, nofailPackBean);
            }
        }
    }
    @Override
    public ResultBean queryMesProductionRecordReport(String organizeCode, String productSn) {

        //查询条码信息, 根据创建时间倒序
        List<MesProduceSn> produceSnList = produceSnExtService.getProduceSnListCreateDatetimeDesc(organizeCode, productSn);

        if (CollectionUtils.isEmpty(produceSnList)) return ResultBean.fail(String.format("零件条码[%s]信息不存在!", productSn));

        MesProduceSn produceSnDb = produceSnList.get(0);

        //查询加工记录, 根据完成时间倒序
        List<MesProductionRecord> productionRecordList = findProductionRecordListCompleteDateTimeDesc(organizeCode, productSn);

        //查询生产线名称
        Map<String, String> workCenterCodeMap = getProductionRecordReportCenterMap(organizeCode, produceSnDb.getWorkCenterCode(), productionRecordList);
        //查询工位名称
        Map<String, String> workCellCodeMap = getProductionRecordReportCellMap(organizeCode, produceSnDb.getWorkCellCode(), productionRecordList);
        //查询工艺名称
        Map<String, String> craftCodeMap = getProductionRecordReportCraftMap(organizeCode, produceSnDb.getCraftCode(), productionRecordList);

        Map<String, Object> produceSnMap = new HashMap<>();
        produceSnMap.put(MesPcnExtConstWords.PRODUCT_SN, productSn);
        produceSnMap.put(MesPcnExtConstWords.PART_NO, produceSnDb.getPartNo());
        produceSnMap.put(MesPcnExtConstWords.PART_NAME, produceSnDb.getPartName());
        produceSnMap.put(MesPcnExtConstWords.WORK_CENTER_CODE, produceSnDb.getWorkCenterCode());
        produceSnMap.put(MesPcnExtConstWords.WORK_CELL_CODE, produceSnDb.getWorkCellCode());
        produceSnMap.put(MesPcnExtConstWords.CRAFT_CODE, produceSnDb.getCraftCode());
        produceSnMap.put(MesPcnExtConstWords.WORK_CENTER_NAME, getMap2Value(workCenterCodeMap, produceSnDb.getWorkCenterCode()));
        produceSnMap.put(MesPcnExtConstWords.WORK_CELL_NAME, getMap2Value(workCellCodeMap, getCellCodeSuffix(produceSnDb.getWorkCenterCode(), produceSnDb.getWorkCellCode())));
        produceSnMap.put(MesPcnExtConstWords.CRAFT_NAME, getMap2Value(craftCodeMap, produceSnDb.getCraftCode()));
        produceSnMap.put(MesPcnExtConstWords.SN_STATUS, produceSnDb.getSnStatus());
        produceSnMap.put(MesPcnExtConstWords.QC_STATUS, produceSnDb.getQcStatus());
        produceSnMap.put(MesPcnExtConstWords.SN_STATUS_NAME, MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSnDb.getSnStatus()));
        produceSnMap.put(MesPcnExtConstWords.QC_STATUS_NAME, MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSnDb.getQcStatus()));
        produceSnMap.put(MesPcnExtConstWords.MODIFY_USER, produceSnDb.getModifyUser());
        produceSnMap.put(MesPcnExtConstWords.MODIFY_DATE_TIME, produceSnDb.getModifyDatetime());

        ResultBean resultBean = ResultBean.success("查询成功!").setResultObject(produceSnMap);

        if (CollectionUtils.isEmpty(productionRecordList)) return resultBean;

        Map<String, List<MesProduceSn>> produceSnMap2Part = produceSnList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).collect(Collectors.groupingBy(MesProduceSn::getPartNo));

        List<Map<String, Object>> productionRecordMapList = new ArrayList<>();

        MesProduceSn produceSnItem;
        for (MesProductionRecord productionRecord : productionRecordList) {
            if (null == productionRecord) continue;
            Map<String, Object> productionRecordMap = new HashMap<>();
            productionRecordMap.put(MesPcnExtConstWords.PRODUCT_SN, productSn);
            productionRecordMap.put(MesPcnExtConstWords.PART_NO, productionRecord.getPartNo());
            productionRecordMap.put(MesPcnExtConstWords.PART_NAME, productionRecord.getPartName());
            productionRecordMap.put(MesPcnExtConstWords.WORK_CENTER_CODE, productionRecord.getWorkCenterCode());
            productionRecordMap.put(MesPcnExtConstWords.WORK_CELL_CODE, productionRecord.getWorkCellCode());
            productionRecordMap.put(MesPcnExtConstWords.CRAFT_CODE, productionRecord.getCraftCode());
            productionRecordMap.put(MesPcnExtConstWords.WORK_CENTER_NAME, getMap2Value(workCenterCodeMap, productionRecord.getWorkCenterCode()));
            productionRecordMap.put(MesPcnExtConstWords.WORK_CELL_NAME, getMap2Value(workCellCodeMap, getCellCodeSuffix(productionRecord.getWorkCenterCode(), productionRecord.getWorkCellCode())));
            productionRecordMap.put(MesPcnExtConstWords.CRAFT_NAME, getMap2Value(craftCodeMap, productionRecord.getCraftCode()));
            if (!CollectionUtils.isEmpty(produceSnMap2Part) && !StringUtils.isEmpty(productionRecord.getPartNo()) && produceSnMap2Part.containsKey(productionRecord.getPartNo())) {
                produceSnItem = produceSnMap2Part.get(productionRecord.getPartNo()).get(0);
                productionRecordMap.put(MesPcnExtConstWords.SN_STATUS, produceSnItem.getSnStatus());
                productionRecordMap.put(MesPcnExtConstWords.QC_STATUS, produceSnItem.getQcStatus());
                productionRecordMap.put(MesPcnExtConstWords.SN_STATUS_NAME, !StringUtils.isEmpty(produceSnItem.getSnStatus()) ? MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSnItem.getSnStatus()) : MesPcnExtConstWords.EMPTY);
                productionRecordMap.put(MesPcnExtConstWords.QC_STATUS_NAME, !StringUtils.isEmpty(produceSnItem.getQcStatus()) ? MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSnItem.getQcStatus()) : MesPcnExtConstWords.EMPTY);
            }
            productionRecordMap.put(MesPcnExtConstWords.COMPLETE_DATE_TIME, productionRecord.getCompleteDateTime());
            productionRecordMap.put(MesPcnExtConstWords.CREATE_USER, productionRecord.getCreateUser());
            productionRecordMap.put(MesPcnExtConstWords.REPORT_STATUS, productionRecord.getReportStatus());
            productionRecordMap.put(MesPcnExtConstWords.REPORT_STATUS_NAME, !StringUtils.isEmpty(productionRecord.getReportStatus()) ? MesExtEnumUtil.REPORT_STATUS.valueOfDescription(productionRecord.getReportStatus()) : MesPcnExtConstWords.EMPTY);
            productionRecordMapList.add(productionRecordMap);
        }

        return resultBean.setResultList(productionRecordMapList);
    }

    private String getCellCodeSuffix(String workCenterCode, String workCellCode) {
        if (StringUtils.isEmpty(workCenterCode) || StringUtils.isEmpty(workCellCode)) return null;
        return new StringJoiner(MesPcnExtConstWords.AND).add(workCenterCode).add(workCellCode).toString();
    }

    private String getMap2Value(Map<String, String> map, String key) {
        if (StringUtils.isEmpty(key)) return MesPcnExtConstWords.EMPTY;
        if (CollectionUtils.isEmpty(map) || !map.containsKey(key)) return MesPcnExtConstWords.EMPTY;
        return map.get(key);
    }

    private Map<String, String> getProductionRecordReportCenterMap(String organizeCode, String workCenterCode, List<MesProductionRecord> productionRecordList) {
        List<String> workCenterCodeList = CollectionUtils.isEmpty(productionRecordList) ? null :
                productionRecordList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCenterCode()))).map(MesProductionRecord::getWorkCenterCode).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(workCenterCodeList) && !StringUtils.isEmpty(workCenterCode)) workCenterCodeList = new ArrayList<>();
        if (!StringUtils.isEmpty(workCenterCode)) workCenterCodeList.add(workCenterCode);
        return prodOrgExtService.getWorkCenterCodeMap(organizeCode, workCenterCodeList);
    }

    private Map<String, String> getProductionRecordReportCellMap(String organizeCode, String workCellCode, List<MesProductionRecord> productionRecordList) {
        List<String> workCellCodeList = CollectionUtils.isEmpty(productionRecordList) ? null :
                productionRecordList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCellCode()))).map(MesProductionRecord::getWorkCellCode).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(workCellCodeList) && !StringUtils.isEmpty(workCellCode)) workCellCodeList = new ArrayList<>();
        if (!StringUtils.isEmpty(workCellCode)) workCellCodeList.add(workCellCode);
        return prodOrgExtService.getWorkCellCodeMap(organizeCode, workCellCodeList);
    }

    private Map<String, String> getProductionRecordReportCraftMap(String organizeCode, String craftCode, List<MesProductionRecord> productionRecordList) {
        List<String> craftCodeList = CollectionUtils.isEmpty(productionRecordList) ? null :
                productionRecordList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCraftCode()))).map(MesProductionRecord::getCraftCode).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(craftCodeList) && !StringUtils.isEmpty(craftCode)) craftCodeList = new ArrayList<>();
        if (!StringUtils.isEmpty(craftCode)) craftCodeList.add(craftCode);
        return prodOrgExtService.getCraftCodeMap(organizeCode, craftCodeList);
    }

    @Override
    public void updateProductionRecord(List<MesProductionRecord> recordList, String userName, Integer reportStatus, String msg) {

        recordList.forEach(record->{
            DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
            DdlPreparedPack.getNumEqualPack(record.getId(), "id", ddlPackBean);

            MesProductionRecord mesProductionRecord = productionRecordRepository.getByProperty(ddlPackBean);
            if (mesProductionRecord !=null && Objects.equals(mesProductionRecord.getReportStatus(), MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_40.getValue())) {
                productionRecordRao.updateByPropertiesNoSync(new String[]{"modifyUser", "modifyDatetime", "reportStatus","remark"},
                        new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), reportStatus,msg}, ddlPackBean);
            } else {
                productionRecordRao.updateByPropertiesNoSync(new String[]{"modifyUser", "modifyDatetime", "reportStatus","remark","systemSyncStatus","systemSyncDatetime"},
                        new Object[]{userName, DateUtil.format(new Date(), MesPcnExtConstWords.DATE_FORMAT_SSS), reportStatus,msg,CommonEnumUtil.FALSE,""}, ddlPackBean);

            }
        });
    }

}
