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

import cn.estsh.i3plus.ext.mes.api.busi.ISxOqcManageService;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.SxOqcBatchModel;
import cn.estsh.i3plus.ext.mes.pojo.model.SxOqcManageModel;
import cn.estsh.i3plus.ext.mes.pojo.model.SxOqcPackageDetailModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pojo.sqlpack.MesExtHqlPack;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 成品出货检验管理
 * 1.PC出货检验只展示已经在PCN标记过结果(合格/不合格)的根据成品条码生成的检验单(分页展示),不展示组件抽检的检验单
 * 2.PC出货检验:a.打开界面默认展示当天的检验单,查询条件包含:生产工单,生产线,物料,检验单号,检验单类型,检验结果,抽检产品条码,创建日期起始,创建日期截止
 *             b.展示列属性包含：序号,工单号,检验单号,检验类型,抽检产品条码,物料编码,物料名称,产品类别,生产线代码,生产日期,班次代码,工单计划数量,抽检数量,抽检范围,已关联范围,检验结果,检验人,检验时间,创建人,创建日期,修改人,修改日期
 *             c.按钮包含:合格,不合格,导出,项目明细,产品明细
 * 3.PC出货检验按钮项目明细:a.选中一行检验单点击按钮弹出开窗界面默认展示选中的检验单下所有的项目明细(分页展示),查询条件包含:检验项目
 *                       b.展示列属性包含：序号,工单号,检验单号,抽检产品条码,物料编码,物料名称,序号,检验项目,判断基准,启用器具,上限值,下限值,检验值,备注,检验结果,创建人,创建日期,修改人,修改日期
 *                       c.按钮包含:导出
 *                       d.编辑只支持修改备注,操作方式:鼠标双击单行的备注处,修改后点击其他行,即光标失焦提交数据
 * 4.PC出货检验按钮产品明细:a.选中一行检验单点击按钮弹出开窗界面默认展示选中的检验单下所有的产品明细(不支持分页展示,默认加载所有产品),查询条件包含:产品条码,包装条码,抽检范围起始,抽检范围截止
 *                       b.展示列属性包含：序号,工单号,检验单号,生产线代码,产品条码,包装条码,检验结果
 *                       c.按钮包含:合格,不合格,导出
 *                       d.合格/不合格:
 *                            按钮操作方式为单行勾选,支持批量勾选操作
 *                            只修改勾选数据的结果,未勾选的数据的结果不做任何处理
 *                            未修改过结果的数据默认为当前检验单的结果(详见第5点)
 *                       e.抽检范围查询逻辑：
 *                            例如条码流水号关联单据的顺序如下: 0001,0003,0009,0007,0005,0011,0002,0004,0099,0100,0006,0008,0012,0013.......
 *                            如果查询 抽检范围起始1 抽检范围截止10 的数据
 *                            则展示前10条数据,且按照产品条码正序展示,即：0001,0002,0003,0004,0005,0007,0009,0011,0099,0100
 * 5.PC出货检验支持跳过修改检验单的结果,直接先修改具体产品的结果,被修改过结果的产品条码的结果不会因检验单的结果变化而变化,未被修改过结果的产品条码的结果默认等于当前检验单的结果
 *   例如:检验单包含100个产品条码,检验单状态是合格,即100个产品条码的状态均为合格,此时直接修改前10个产品条码为不合格,当前即前10个产品为不合格,后90个为合格
 *       此时修改检验单的状态为不合格,当前即前10个产品为不合格,后90个跟随检验单的状态变更为不合格,即所有条码均为不合格
 *       此时再次修改检验单的状态为合格,当前即前10个产品的结果仍然保持不变,为不合格,后90个跟随检验单的状态变更为合格,即前10个产品为不合格,后90个为合格
 *
 * 组件出货检验管理
 * 1.PC出货检验只展示已经在PCN标记过结果(合格/不合格)的组件类型的检验单(分页展示),不展示成品抽检的检验单
 * 2.PC出货检验:a.打开界面默认展示当天的检验单,查询条件包含:生产工单,生产线,物料,检验单号,检验单类型,检验结果,创建日期起始,创建日期截止
 *             b.展示列属性包含：序号,工单号,检验单号,检验类型,物料编码,物料名称,产品类别,生产线代码,生产日期,班次代码,工单计划数量,抽检数量,抽检范围,检验结果,检验人,检验时间,创建人,创建日期,修改人,修改日期
 *             c.按钮包含:合格,不合格,导出,项目明细
 * 3.PC出货检验按钮项目明细:a.选中一行检验单点击按钮弹出开窗界面默认展示选中的检验单下所有的项目明细(分页展示),查询条件包含:检验项目
 *                       b.展示列属性包含：序号,工单号,检验单号,物料编码,物料名称,序号,检验项目,判断基准,启用器具,上限值,下限值,检验值,备注,检验结果,创建人,创建日期,修改人,修改日期
 *                       c.按钮包含:导出
 *                       d.编辑只支持修改备注,操作方式:鼠标双击单行的备注处,修改后点击其他行,即光标失焦提交数据
 *
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class SxOqcManageService implements ISxOqcManageService {

    @Autowired
    private MesOqcCheckRepository oqcCheckRepository;

    @Autowired
    private MesOqcCheckDetailRepository oqcCheckDetailRepository;

    @Autowired
    private MesOqcPackageDetailRepository oqcPackageDetailRepository;

    @Autowired
    private SxUpdateOqcBatchRepository sxUpdateOqcBatchRepository;

    @Autowired
    private SxUpdateOqcSingleRepository sxUpdateOqcSingleRepository;

    @Override
    public ListPager<SxOqcManageModel> queryOqcCheckPager(SxOqcManageModel model, Pager pager) {
        List<SxOqcManageModel> resultList = new ArrayList<>();
        DdlPackBean hqlPack = MesExtHqlPack.getOqcCheck(model);
        pager = PagerHelper.getPager(pager, oqcCheckRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by createDatetime desc ");
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWherePage(hqlPack, pager);
        if (!CollectionUtils.isEmpty(oqcCheckList)) {
            for (MesOqcCheck oqcCheck : oqcCheckList) {
                if (null == oqcCheck) {
                    continue;
                }
                SxOqcManageModel result = new SxOqcManageModel();
                BeanUtils.copyProperties(oqcCheck, result);
                result.setOqcTypeName(MesExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(oqcCheck.getOqcType()));
                result.setCheckResultName(MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheck.getCheckResult()));
                resultList.add(result);
            }
        }
        return new ListPager(resultList, pager);
    }

    @Override
    public void updateOqcCheckResult(SxOqcManageModel model, String userName) {
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单ID[%s]数据不存在", model.getId())
                    .build();
        }
        if (StringUtils.isEmpty(oqcCheckDb.getCheckResult()) || null == MesExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheckDb.getCheckResult())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]数据未经过工位端处理,操作失败", oqcCheckDb.getOqcNo())
                    .build();
        }
        if (oqcCheckDb.getCheckResult() == model.getCheckResult()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]已经是[%s]状态,操作失败",
                            oqcCheckDb.getOqcNo(), MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult()))
                    .build();
        }
        oqcCheckDb.setCheckResult(model.getCheckResult());
        ConvertBean.serviceModelUpdate(oqcCheckDb, userName);
        oqcCheckRepository.save(oqcCheckDb);

        SxUpdateOqcBatch sxUpdateOqcBatch = new SxUpdateOqcBatch();
        sxUpdateOqcBatch.setOqcNo(oqcCheckDb.getOqcNo());
        sxUpdateOqcBatch.setWorkOrderNo(oqcCheckDb.getWorkOrderNo());
        sxUpdateOqcBatch.setWorkTime(oqcCheckDb.getWorkTime());
        sxUpdateOqcBatch.setShiftCode(oqcCheckDb.getShiftCode());
        sxUpdateOqcBatch.setCheckResult(model.getCheckResult());
        sxUpdateOqcBatch.setSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        sxUpdateOqcBatch.setOrganizeCode(oqcCheckDb.getOrganizeCode());
        ConvertBean.serviceModelInitialize(sxUpdateOqcBatch, userName);
        sxUpdateOqcBatchRepository.insert(sxUpdateOqcBatch);

    }

    @Override
    public ListPager<MesOqcCheckDetail> queryOqcCheckDetailPager(MesOqcCheckDetail detail, Pager pager) {
        DdlPackBean hqlPack = MesExtHqlPack.getOqcCheckDetail(detail);
        pager = PagerHelper.getPager(pager, oqcCheckDetailRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by seq asc ");
        List<MesOqcCheckDetail> oqcCheckDetailList = oqcCheckDetailRepository.findByHqlWherePage(hqlPack, pager);
        //if (!CollectionUtils.isEmpty(oqcCheckDetailList)) {
        //    for (MesOqcCheckDetail item : oqcCheckDetailList) {
        //        if (null == item) {
        //            continue;
        //        }
        //        item.setResultName(StringUtils.isEmpty(item.getResult()) ? null : MesExtEnumUtil.CHECK_RESULT.valueOfDescription(item.getResult()));
        //    }
        //}
        return new ListPager(oqcCheckDetailList, pager);
    }

    @Override
    public void updateOqcCheckDetailRemark(MesOqcCheckDetail detail, String userName) {
        MesOqcCheckDetail oqcCheckDetailDb = oqcCheckDetailRepository.getById(detail.getId());
        if (null == oqcCheckDetailDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单项目ID[%s]数据不存在", detail.getId())
                    .build();
        }
        oqcCheckDetailDb.setRemark(detail.getRemark());
        ConvertBean.serviceModelUpdate(oqcCheckDetailDb, userName);
        oqcCheckDetailRepository.save(oqcCheckDetailDb);
    }

    @Override
    public List<SxOqcPackageDetailModel> queryOqcPackageDetailList(SxOqcManageModel model) {
        List<SxOqcPackageDetailModel> resultList = null;
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单ID[%s]数据不存在", model.getId())
                    .build();
        }
        List<MesOqcPackageDetail> oqcPackageDetailList = oqcPackageDetailRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), oqcCheckDb.getOqcNo()},
                " order by createDatetime asc, serialNumber asc ");
        if (CollectionUtils.isEmpty(oqcPackageDetailList)) {
            return resultList;
        }
        if (!StringUtils.isEmpty(model.getBatchLimitStart())) {
            if (model.getBatchLimitStart().compareTo(0) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围起始必须大于0")
                        .build();
            }
            if (model.getBatchLimitStart().compareTo(Integer.valueOf(oqcPackageDetailList.size())) > 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围起始必须小于等于已关联范围")
                        .build();
            }
        }
        if (!StringUtils.isEmpty(model.getBatchLimitEnd())) {
            if (model.getBatchLimitEnd().compareTo(0) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围截止必须大于0")
                        .build();
            }
            if (model.getBatchLimitEnd().compareTo(Integer.valueOf(oqcPackageDetailList.size())) > 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围截止必须小于等于已关联范围")
                        .build();
            }
        }
        if (!StringUtils.isEmpty(model.getBatchLimitStart()) && !StringUtils.isEmpty(model.getBatchLimitEnd())) {
            if (model.getBatchLimitStart().compareTo(model.getBatchLimitEnd()) > 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围起始必须小于等于抽检范围截止")
                        .build();
            }
        }

        if (StringUtils.isEmpty(model.getBatchLimitStart())) {
            model.setBatchLimitStart(1);
        }
        if (StringUtils.isEmpty(model.getBatchLimitEnd())) {
            model.setBatchLimitEnd(Integer.valueOf(oqcPackageDetailList.size()));
        }

        oqcPackageDetailList = oqcPackageDetailList.subList(model.getBatchLimitStart() - 1, model.getBatchLimitEnd());

        if (!StringUtils.isEmpty(model.getSerialNumber())) {
            oqcPackageDetailList = oqcPackageDetailList.stream().filter(o -> (null != o && o.getSerialNumber().equals(model.getSerialNumber()))).collect(Collectors.toList());
        }
        if (!StringUtils.isEmpty(model.getPackageNo())) {
            oqcPackageDetailList = oqcPackageDetailList.stream().filter(o -> (null != o && o.getPackageNo().equals(model.getPackageNo()))).collect(Collectors.toList());
        }

        if (!CollectionUtils.isEmpty(oqcPackageDetailList)) {
            for (MesOqcPackageDetail item : oqcPackageDetailList) {
                if (null == item) {
                    continue;
                }

                SxOqcPackageDetailModel result = new SxOqcPackageDetailModel();
                BeanUtils.copyProperties(item, result);
                result.setCheckResultName(StringUtils.isEmpty(item.getCheckResult())
                        ? MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult())
                        : MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(item.getCheckResult()));
                if (CollectionUtils.isEmpty(resultList)) {
                    resultList = new ArrayList<>();
                }
                resultList.add(result);
            }
        }
        return resultList;
    }

    @Override
    public void updateOqcPackageDetailResult(SxOqcBatchModel model, String userName) {
        if (CollectionUtils.isEmpty(model.getIdList())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("请先勾选产品数据")
                    .build();
        }
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]数据不存在", model.getOqcNo())
                    .build();
        }
        if (StringUtils.isEmpty(oqcCheckDb.getCheckResult()) || null == MesExtEnumUtil.OQC_CHECK_RESULT.getByValue(oqcCheckDb.getCheckResult())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]数据未经过工位端处理,操作失败", oqcCheckDb.getOqcNo())
                    .build();
        }

        List<MesOqcPackageDetail> oqcPackageDetailList = oqcPackageDetailRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        Map<Long, MesOqcPackageDetail> idMap = CollectionUtils.isEmpty(oqcPackageDetailList) ? new HashMap<>() :
                oqcPackageDetailList.stream().filter(o -> null != o).collect(Collectors.toMap(MesOqcPackageDetail::getId, o -> o));

        for (Long id : model.getIdList()) {
            if (StringUtils.isEmpty(id)) {
                continue;
            }
            MesOqcPackageDetail oqcPackageDetail = idMap.get(id);
            if (null == oqcPackageDetail) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("产品ID[%s]数据不存在", id)
                        .build();
            }

            oqcPackageDetail.setCheckResult(model.getCheckResult());
            ConvertBean.serviceModelUpdate(oqcPackageDetail, userName);
            oqcPackageDetailRepository.save(oqcPackageDetail);

            SxUpdateOqcSingle sxUpdateOqcSingle = new SxUpdateOqcSingle();
            sxUpdateOqcSingle.setOqcNo(oqcPackageDetail.getOqcNo());
            sxUpdateOqcSingle.setSerialNumber(oqcPackageDetail.getSerialNumber());
            sxUpdateOqcSingle.setPackageNo(oqcPackageDetail.getPackageNo());
            sxUpdateOqcSingle.setPartNo(oqcCheckDb.getPartNo());
            sxUpdateOqcSingle.setCheckResult(model.getCheckResult());
            sxUpdateOqcSingle.setWorkOrderNo(oqcCheckDb.getWorkOrderNo());
            sxUpdateOqcSingle.setSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            sxUpdateOqcSingle.setOrganizeCode(oqcCheckDb.getOrganizeCode());
            ConvertBean.serviceModelInitialize(sxUpdateOqcSingle, userName);
            sxUpdateOqcSingleRepository.insert(sxUpdateOqcSingle);
        }

    }
}
