package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.base.bu3;

import cn.estsh.i3plus.ext.mes.api.base.IProdOrgExtService;
import cn.estsh.i3plus.ext.mes.api.base.bu3.ISxOfficialLossDetailRecordService;
import cn.estsh.i3plus.ext.mes.api.busi.bu3.ISxPartExtService;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesOfficialLossDetailRecord;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesPartExt;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesWorkCenterExt;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.SxOfficialLossDetailRecordModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesOfficialLossDetailRecordRepository;
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.mes.api.iservice.base.IConfigService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
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.i3plus.pojo.mes.bean.MesConfig;
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;

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class SxOfficialLossDetailRecordService implements ISxOfficialLossDetailRecordService {

    @Autowired
    private MesOfficialLossDetailRecordRepository officialLossDetailRecordRepository;

    @Autowired
    private IConfigService configService;

    @Autowired
    private ISxPartExtService partExtService;

    @Autowired
    private IProdOrgExtService prodOrgExtService;

    @Override
    public ListPager<SxOfficialLossDetailRecordModel> queryOfficialLossDetailRecordByPager(SxOfficialLossDetailRecordModel officialLossDetailRecord, Pager pager) {
        List<SxOfficialLossDetailRecordModel> resultList = new ArrayList<>();
        DdlPackBean hqlPack = MesExtHqlPack.getOfficialLossDetailRecord(officialLossDetailRecord);
        pager = PagerHelper.getPager(pager, officialLossDetailRecordRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by createDatetime desc ");
        List<MesOfficialLossDetailRecord> officialLossDetailRecordList = officialLossDetailRecordRepository.findByHqlWherePage(hqlPack, pager);
        if (!CollectionUtils.isEmpty(officialLossDetailRecordList)) packResultList(officialLossDetailRecord.getOrganizeCode(), resultList, officialLossDetailRecordList);
        return new ListPager(resultList, pager);
    }

    private List<SxOfficialLossDetailRecordModel> packResultList(String organizeCode, List<SxOfficialLossDetailRecordModel> resultList, List<MesOfficialLossDetailRecord> officialLossDetailRecordList) {
        Map<String, Map<String, String>> itemCfgMap = getOfficialLossItemCfgMap(organizeCode);
        for (MesOfficialLossDetailRecord item : officialLossDetailRecordList) {
            if (null == item) continue;
            SxOfficialLossDetailRecordModel result = new SxOfficialLossDetailRecordModel();
            BeanUtils.copyProperties(item, result);
            result.setIdStr(item.getId().toString());
            result.setLossTypeName(!StringUtils.isEmpty(result.getLossType()) ? MesExtEnumUtil.SX_OFFICIAL_LOSS_TYPE.valueOfDescription(result.getLossType()) : null);
            result.setLossItemName(!StringUtils.isEmpty(result.getLossItem()) ? (!CollectionUtils.isEmpty(itemCfgMap) && itemCfgMap.containsKey(result.getLossType()) ? itemCfgMap.get(result.getLossType()).get(result.getLossItem()) : null) : null);
            resultList.add(result);
        }
        return resultList;
    }

    @Override
    public MesOfficialLossDetailRecord insertOfficialLossDetailRecord(SxOfficialLossDetailRecordModel officialLossDetailRecord) {
        checkValue(officialLossDetailRecord);
        Double partPrice = getPartPrice(officialLossDetailRecord.getOrganizeCode(), officialLossDetailRecord.getPartNo());
        MesWorkCenterExt workCenterExt = getWorkCenter(officialLossDetailRecord.getOrganizeCode(), officialLossDetailRecord.getWorkCenterCode());
        MesOfficialLossDetailRecord record = new MesOfficialLossDetailRecord();
        BeanUtils.copyProperties(officialLossDetailRecord, record);
        record.setUnitPrice(partPrice);
        record.setAmount(MathOperation.mul(record.getQty(), record.getUnitPrice()));
        record.setCareerCode(workCenterExt.getCareerCode());
        record.setCategoryCode(workCenterExt.getCategoryCode());
        record.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelInitialize(record, officialLossDetailRecord.getCreateUser());
        record = officialLossDetailRecordRepository.insert(record);
        return record;
    }

    private MesWorkCenterExt getWorkCenter(String organizeCode, String workCenterCode) {
        MesWorkCenterExt workCenterExt = prodOrgExtService.getWorkCenterExt(organizeCode, workCenterCode);
        if (null == workCenterExt)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线代码[%s]信息不存在", workCenterCode)
                    .build();
        if (StringUtils.isEmpty(workCenterExt.getCareerCode()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线代码[%s]信息未维护事业别", workCenterCode)
                    .build();
        if (StringUtils.isEmpty(workCenterExt.getCategoryCode()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线代码[%s]信息未维护产品别", workCenterCode)
                    .build();
        return workCenterExt;
    }

    private Double getPartPrice(String organizeCode, String partNo) {
        MesPartExt partExt = partExtService.getPartExtByPartNo(organizeCode, partNo);
        if (null == partExt)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("物料编码[%s]信息不存在", partNo)
                    .build();
        if (StringUtils.isEmpty(partExt.getPartPrice()) || MathOperation.compareTo(partExt.getPartPrice(), new Double(0)) <= 0)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("物料编码[%s]未同步WMS的部品单价", partNo)
                    .build();
        return partExt.getPartPrice();
    }

    private void checkValue(SxOfficialLossDetailRecordModel officialLossDetailRecord) {
        if (MathOperation.compareTo(officialLossDetailRecord.getQty(), new Double(0)) <= 0)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("报废数量[%s]必须是正数", officialLossDetailRecord.getQty())
                    .build();
        String[] qtyArr = officialLossDetailRecord.getQty().toString().split(MesExtConstWords.DECIMAL_POINT);
        if (qtyArr.length == 2 && qtyArr[1].length() > 3)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("报废数量[%s]最多三位小数", officialLossDetailRecord.getQty())
                    .build();
    }

    @Override
    public MesOfficialLossDetailRecord updateOfficialLossDetailRecord(SxOfficialLossDetailRecordModel officialLossDetailRecord) {
        checkValue(officialLossDetailRecord);
        Double partPrice = getPartPrice(officialLossDetailRecord.getOrganizeCode(), officialLossDetailRecord.getPartNo());
        MesWorkCenterExt workCenterExt = getWorkCenter(officialLossDetailRecord.getOrganizeCode(), officialLossDetailRecord.getWorkCenterCode());
        MesOfficialLossDetailRecord record = officialLossDetailRecordRepository.getById(Long.parseLong(officialLossDetailRecord.getIdStr()));
        if (null == record)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录不存在", officialLossDetailRecord.getIdStr())
                    .build();
        record.setWorkCenterCode(officialLossDetailRecord.getWorkCenterCode());
        record.setLossDate(officialLossDetailRecord.getLossDate());
        record.setLossType(officialLossDetailRecord.getLossType());
        record.setLossItem(officialLossDetailRecord.getLossItem());
        record.setPartNo(officialLossDetailRecord.getPartNo());
        record.setPartNameRdd(officialLossDetailRecord.getPartNameRdd());
        record.setQty(officialLossDetailRecord.getQty());
        record.setUnitPrice(partPrice);
        record.setAmount(MathOperation.mul(record.getQty(), record.getUnitPrice()));
        record.setCareerCode(workCenterExt.getCareerCode());
        record.setCategoryCode(workCenterExt.getCategoryCode());
        record.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelUpdate(record, officialLossDetailRecord.getModifyUser());
        return officialLossDetailRecordRepository.save(record);
    }

    @Override
    public void updateOfficialLossDetailRecordValidById(String[] idStrArr, Integer status, String userName) {
        if (status != CommonEnumUtil.IS_VAILD.INVAILD.getValue() && status != CommonEnumUtil.IS_VAILD.VAILD.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("启用，禁用枚举状态值【%s】未被定义", status)
                    .build();
        }

        for (String idStr : idStrArr) {
            MesOfficialLossDetailRecord officialLossDetailRecordDb = officialLossDetailRecordRepository.getById(Long.parseLong(idStr));
            if (null == officialLossDetailRecordDb)
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("ID[%s]对应的记录不存在", idStr)
                        .build();
            officialLossDetailRecordDb.setIsValid(status);
            officialLossDetailRecordDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(officialLossDetailRecordDb, userName);
            officialLossDetailRecordRepository.save(officialLossDetailRecordDb);
        }
    }

    @Override
    public void deleteOfficialLossDetailRecordById(String[] idStrArr, String userName) {
        for (String idStr : idStrArr) {
            MesOfficialLossDetailRecord officialLossDetailRecordDb = officialLossDetailRecordRepository.getById(Long.parseLong(idStr));
            if (null == officialLossDetailRecordDb)
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("ID[%s]对应的记录不存在", idStr)
                        .build();
            officialLossDetailRecordDb.setIsDeleted(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            officialLossDetailRecordDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(officialLossDetailRecordDb, userName);
            officialLossDetailRecordRepository.save(officialLossDetailRecordDb);
        }
    }

    @Override
    public Map<String, Map<String, String>> getOfficialLossItemCfgMap(String organizeCode) {
        List<MesConfig> configList = configService.findConfigsByCfgCode(MesExtConstWords.SX_OFFICIAL_LOSS_TYPE_ITEM_CFG, organizeCode);
        Map<String, List<MesConfig>> typeMap = CollectionUtils.isEmpty(configList) ? null :
                configList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCfgType()) && !StringUtils.isEmpty(o.getCfgKey()) && !StringUtils.isEmpty(o.getCfgValue()))).collect(Collectors.groupingBy(MesConfig::getCfgType));
        if (CollectionUtils.isEmpty(typeMap)) return null;
        Map<String, Map<String, String>> itemCfgMap = new HashMap<>();
        for (Map.Entry<String, List<MesConfig>> entry : typeMap.entrySet()) {
            if (null == entry) continue;
            Map<String, String> itemMap = new HashMap<>();
            for (MesConfig item : entry.getValue()) {
                if (null == item) continue;
                itemMap.put(item.getCfgKey(), item.getCfgValue());
            }
            itemCfgMap.put(entry.getKey(), itemMap);
        }
        return itemCfgMap;
    }

    @Override
    public List<SxOfficialLossDetailRecordModel> getOfficialLossDetailRecordList(SxOfficialLossDetailRecordModel officialLossDetailRecord) {
        DdlPackBean hqlPack = MesExtHqlPack.getOfficialLossDetailRecord(officialLossDetailRecord);
        List<MesOfficialLossDetailRecord> officialLossDetailRecordList = officialLossDetailRecordRepository.findByHqlWhere(hqlPack);
        return !CollectionUtils.isEmpty(officialLossDetailRecordList) ? packResultList(officialLossDetailRecord.getOrganizeCode(), new ArrayList<>(), officialLossDetailRecordList) : null;
    }

}
