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

import com.alibaba.fastjson.JSON;
import com.rongwei.bscommon.sys.config.LinkedServerConfig;
import com.rongwei.bscommon.sys.dao.QuShiftLeaderDao;
import com.rongwei.bscommon.sys.dao.QuestionCommonSqlDao;
import com.rongwei.bscommon.sys.dao.sqlserver.QUADao;
import com.rongwei.bscommon.sys.service.MesDataSyncService;
import com.rongwei.bscommon.sys.utils.NoticeUtils;
import com.rongwei.bscommon.sys.utils.QuestionUtils;
import com.rongwei.bsentity.domin.QuShiftLeaderDo;
import com.rongwei.bsentity.domin.QuSyncMesErrorDo;
import com.rongwei.bsentity.domin.SrmIssuesListDo;
import com.rongwei.bsentity.vo.FiveWhyVo;
import com.rongwei.bsentity.vo.QUAVo;
import com.rongwei.rwadmincommon.system.domain.SysOrganizationDo;
import com.rongwei.rwadmincommon.system.domain.SysUserDo;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.rongwei.bscommon.sys.utils.QuestionConstants.FACTORY_NAME;
import static com.rongwei.bscommon.sys.utils.QuestionConstants.MES.DEFAULT_USER;
import static com.rongwei.bscommon.sys.utils.QuestionConstants.MES.QUA_TABLE_NAME;
import static com.rongwei.bscommon.sys.utils.QuestionConstants.ProblemLevel.WORKSHOP;
import static com.rongwei.bscommon.sys.utils.QuestionConstants.TriggerLevel.PS;
import static com.rongwei.bscommon.sys.utils.QuestionUtils.save5W1H;

/**
 * MesDataSyncService class
 *
 * @author XH
 * @date 2023/03/25
 */
@RefreshScope
@Service
public class MesQUADataSyncServiceImpl implements MesDataSyncService {
    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    private QUADao quaDao;
    @Autowired
    private LinkedServerConfig linkedServerConfig;
    @Autowired
    private SrmIssuesListServiceImpl srmIssuesListService;
    @Autowired
    private QuShiftLeaderDao quShiftLeaderDao;
    @Autowired
    private QuSyncMesErrorServiceImpl quSyncMesErrorService;
    @Autowired
    private QuestionCommonSqlDao questionCommonSqlDao;
    @Autowired
    private NoticeUtils noticeUtils;

    public static final BigDecimal QUA_SCRAP_STANDARD = new BigDecimal("1000");
    public static final BigDecimal QUA_SPECIAL_STANDARD = new BigDecimal("2000");
    public static final String QUESTION_TITLE = "卷号:%s----缺陷名称:%s----不合格描述:%s";
    // 可以触发质量报废的机台编号
    public static final List<String> TRIGGER_REASON_MACHINE = new ArrayList<String>() {{
        add("CAST");
        add("SCALP");
        add("SAW");
        add("CLAD");
        add("HOTMILL");
        add("PREHEATING");
        add("COLDMILL");
        add("HGS");
        add("LEVELING");
        add("CTL");
        add("HPS");
        add("ANNEAL");
        add("ILGS");
        add("PACKING");
        add("PACK_SPLIT");
        add("INSPECTION");
    }};
    // 报废指标大于2000的工段
    public static final List<String> EH_SECTION = new ArrayList<String>() {{
        add("CAST");
        add("SCALP");
        add("SAW");
        add("CLAD");
        add("HOTMILL");
        add("PREHEATING");
        add("COLDMILL");
    }};


    /**
     * 质量报废同步逻辑
     *
     * @param startDate
     * @param endDate
     */
    @Override
    public void syncMesData(Date startDate, Date endDate) {
        // 如果没有传 时间格式 默认用 当前时间-3天 作为起始时间
        if (startDate == null || endDate == null) {
            endDate = new Date();
            Calendar cal = Calendar.getInstance();
            cal.setTime(endDate);
            cal.add(Calendar.DATE, -3);// 24小时制
            startDate = cal.getTime();
        }
        // 获取时间段内的所有质量报废信息
        List<QUAVo> quaVos = quaDao.selectInfoByDate(linkedServerConfig.getDBLink(), linkedServerConfig.getDataBaseName(),
                linkedServerConfig.getDataBaseModel(), startDate, endDate, QUA_SCRAP_STANDARD);
        if (quaVos.isEmpty()) {
            log.debug("时间段内：{}-{}暂无报废记录", startDate, endDate);
            return;
        }
        log.debug("获取到质量报废记录：{}", quaVos);
        // 筛选出机台号对应的数据
        quaVos = quaVos.stream().filter(info -> TRIGGER_REASON_MACHINE.contains(info.getNcReasonMachine().toUpperCase(Locale.ROOT))).collect(Collectors.toList());
        List<String> mesIds = quaVos.stream().map(QUAVo::getUuid).distinct().collect(Collectors.toList());
        if (mesIds.isEmpty()) {
            log.error("当前时间范围无法获取到数据,开始时间：{}结束时间：{}", startDate, endDate);
            return;
        }
        // 根据mesId 获取 问题列表判断当前问题是已经记录过
        List<SrmIssuesListDo> srmIssuesRecord = srmIssuesListService.getListByMesId(mesIds);
        // 获取班组对应的员工信息
        List<QuShiftLeaderDo> quShiftLeaderDos = quShiftLeaderDao.selectList(null);
        if (quShiftLeaderDos.isEmpty()) {
            log.debug("排班信息为空");
            QuSyncMesErrorDo errorDo = new QuSyncMesErrorDo();
            errorDo.setId(SecurityUtil.getUUID());
            errorDo.setDeleted("0");
            errorDo.setErrordesc("班组信息为空");
            errorDo.setMesid(quaVos.stream().map(QUAVo::getUuid).collect(Collectors.joining(",")));
            errorDo.setMestablename(QUA_TABLE_NAME);
            return;
        }
        // 获取组织机构
        List<String> orgIs = Stream.concat(quShiftLeaderDos.stream().map(QuShiftLeaderDo::getSection), quShiftLeaderDos.stream().map(QuShiftLeaderDo::getWorkshop)).distinct().collect(Collectors.toList());
        // 获取班组对应的组织机构信息
        List<SysOrganizationDo> orgInfo = questionCommonSqlDao.getOrgInfo(orgIs);

        // 同步失败的 数据信息
        List<QuSyncMesErrorDo> quSyncMesErrorList = new ArrayList<>();
        // 需要加入issue 列表的记录
        List<SrmIssuesListDo> saveIssueList = new ArrayList<>();
        List<FiveWhyVo> fiveWhyVoList = new ArrayList<>();
        /**
         * 1.先筛选出报废重量大于等于1000的 数据
         * 2. 当机台号为空时 默认CAST机台
         * 3. 熔铸 铣面机(加工工段) 热轧质量 冷轧报废 4个机台报废标准为2000 其他都是1000
         */
        List<QUAVo> noBasicErrorData = filterQuaBasicErrorData(quaVos, quSyncMesErrorList, srmIssuesRecord);
        noBasicErrorData.stream().filter(info -> info.getNcWeight().compareTo(QUA_SCRAP_STANDARD) >= 0).forEach(info -> {
            // 根据创建人获取排班信息
            String createUser = info.getCreateUser();
            // 根据班组获取对应的班别信息
            List<QuShiftLeaderDo> quShiftLeaderList = quShiftLeaderDos.stream()
                    .filter(shift -> createUser.equals(shift.getShiftleader()))
                    .collect(Collectors.toList());
            if (quShiftLeaderList.isEmpty()) {
                log.debug("没有获取到员工 :{}对应的排班信息", createUser);
                quSyncMesErrorList.add(orgErrorDo(info.getUuid(), String.format("没有获取到员工 :{%s}对应的排班信息", createUser)));
                return;
            }
            // 获取产生数据的工段 英文编码
            String ncReasonMachine = info.getNcReasonMachine();
            List<SysOrganizationDo> orgInfoByRoptionCode = getOrgInfoByRoptionCode(orgInfo, ncReasonMachine);
            if (orgInfoByRoptionCode.size() != 1) {
                log.debug("根据机台号: {}没有获取到工段信息或获取到多个工段信息", ncReasonMachine);
                quSyncMesErrorList.add(orgErrorDo(info.getUuid(), String.format("根据机台号: {%s}没有获取到工段信息或获取到多个工段信息", ncReasonMachine)));
                return;
            }
            // 工段信息
            SysOrganizationDo section = orgInfoByRoptionCode.get(0);
            SrmIssuesListDo srmIssuesListDo = recordIssue(info, quShiftLeaderList.get(0), section);
            if (srmIssuesListDo != null) {
                saveIssueList.add(srmIssuesListDo);
                FiveWhyVo fiveWhyVo = new FiveWhyVo();
                fiveWhyVo.setId(srmIssuesListDo.getId());
                fiveWhyVo.setWhoDesc(info.getCreateUser());
                fiveWhyVo.setWhatDesc(info.getCoilNo() + "-" + info.getNcReasonDesc());
                fiveWhyVoList.add(fiveWhyVo);
            }
        });
        // 存表
        save5W1H(saveIssueList.stream().map(SrmIssuesListDo::getId).collect(Collectors.toList()), fiveWhyVoList);
        srmIssuesListService.saveBatch(saveIssueList);
        quSyncMesErrorService.saveBatch(quSyncMesErrorList);

        //消息提醒
        noticeUtils.notice(saveIssueList);
    }


    private SrmIssuesListDo recordIssue(QUAVo quaData, QuShiftLeaderDo quShiftLeaderDo, SysOrganizationDo section) {
        // 特殊工段大于2000时记录  正常大于1000时记录
        boolean hasRecord = EH_SECTION.contains(quaData.getNcReasonMachine()) ?
                quaData.getNcWeight().compareTo(QUA_SPECIAL_STANDARD) >= 0 : quaData.getNcWeight().compareTo(QUA_SCRAP_STANDARD) >= 0;
        if (!hasRecord) {
            log.error("当前数据：{},不满足质量报废重量要求", quaData);
            return null;
        }
        SrmIssuesListDo srmIssuesListDo = new SrmIssuesListDo();
        srmIssuesListDo.setId(SecurityUtil.getUUID());
        // 问题分类
        srmIssuesListDo.setTriggerlevel(PS);
        // 类型 车间级
        srmIssuesListDo.setLevle(WORKSHOP);
        srmIssuesListDo.setFailuredate(quaData.getNcDate());
        srmIssuesListDo.setDisqualification(quaData.getNcWeight());
        srmIssuesListDo.setPsinitiator(quaData.getCreateUser());
        srmIssuesListDo.setPsinitiatorid(quShiftLeaderDo.getLeaderid());
        srmIssuesListDo.setCreatedate(new Date());
        srmIssuesListDo.setModifydate(new Date());
        srmIssuesListDo.setCreateuserid(DEFAULT_USER);
        srmIssuesListDo.setCreateusername(DEFAULT_USER);
        srmIssuesListDo.setModifyusername(DEFAULT_USER);
        srmIssuesListDo.setModifyuserid(DEFAULT_USER);
        srmIssuesListDo.setFactory(FACTORY_NAME);
        srmIssuesListDo.setMesid(quaData.getUuid());
        srmIssuesListDo.setFollowupdays("30");
        srmIssuesListDo.setWorkshopordepartment(quShiftLeaderDo.getWorkshop());
        srmIssuesListDo.setWorkshopsection(section.getId());
        // modify at [ 2023-10-19 13:49:12 ] by xh: 改为直接使用缺陷名称
        srmIssuesListDo.setQuestiontitle(quaData.getNcDesc());
        //srmIssuesListDo.setQuestiontitle(String.format(QUESTION_TITLE, quaData.getCoilNo(), quaData.getNcDesc(), quaData.getNcReasonDesc()));
        srmIssuesListDo.setIssuestatus("10");
        List<SysUserDo> dept_ps_admin = QuestionUtils.getPSManagerByOrgId(section, "dept_ps_admin");
        // PS负责人
        srmIssuesListDo.setDeppsresperson(dept_ps_admin.stream().map(SysUserDo::getName).collect(Collectors.joining(",")));
        srmIssuesListDo.setDeppsrespersonids(dept_ps_admin.stream().map(SysUserDo::getId).collect(Collectors.joining(",")));
        List<SysUserDo> dept_leader = QuestionUtils.getPSManagerByOrgId(section, "dept_leader");
        // 部门经理
        srmIssuesListDo.setLeader(dept_leader.stream().map(SysUserDo::getName).collect(Collectors.joining(",")));
        srmIssuesListDo.setTenantid(dept_leader.stream().map(SysUserDo::getId).collect(Collectors.joining(",")));
        //srmIssuesListDo.setQuestionno(QuestionUtils.streamCodeGeneration("srm_issues_list_QUESTIONNO", "@{date:yyyy}@{serialNumber:#000}"));
        return srmIssuesListDo;
    }

    /**
     * 筛选出质量报废有数据错误的数据
     *
     * @param quaVos
     * @param quSyncMesErrorDaos
     * @param srmIssuesRecord    已生成过记录的问题信息
     * @return
     */
    private List<QUAVo> filterQuaBasicErrorData(List<QUAVo> quaVos, List<QuSyncMesErrorDo> quSyncMesErrorDaos,
                                                List<SrmIssuesListDo> srmIssuesRecord) {
        // 报废重量为空的数据
        List<String> emptyWeightData = quaVos.stream()
                .filter(info -> info.getNcWeight() == null)
                .map(QUAVo::getUuid)
                .collect(Collectors.toList());
        // 创建记录为空的数据
        List<String> emptyCreateUserData = quaVos.stream()
                .filter(info -> StringUtils.isBlank(info.getCreateUser()))
                .map(QUAVo::getUuid)
                .collect(Collectors.toList());
        // 机台为空默认Cast
        quaVos.forEach(info -> {
            if (StringUtils.isBlank(info.getNcReasonMachine())) {
                info.setNcReasonMachine("Cast");
            }
        });
        if (!emptyWeightData.isEmpty()) {
            quSyncMesErrorDaos.add(orgErrorDo(String.join(",", emptyWeightData), "报废重量为空"));
        }
        if (!emptyCreateUserData.isEmpty()) {
            quSyncMesErrorDaos.add(orgErrorDo(String.join(",", emptyCreateUserData), "记录创建人为空"));
        }
        List<String> errorIds = emptyWeightData;
        errorIds.addAll(emptyCreateUserData);
        errorIds.addAll(srmIssuesRecord.stream().map(SrmIssuesListDo::getMesid).collect(Collectors.toList()));
        return quaVos.stream().filter(info -> !errorIds.contains(info.getUuid()))
                .filter(info -> info.getNcWeight().compareTo(EH_SECTION.contains(info.getNcReasonMachine()) ? QUA_SPECIAL_STANDARD : QUA_SCRAP_STANDARD) >= 0)
                .collect(Collectors.toList());
    }

    /**
     * 组织错误数据
     *
     * @param id
     * @param errorDesc
     * @param tableName
     * @return
     */
    private QuSyncMesErrorDo orgErrorDo(String id, String errorDesc) {
        QuSyncMesErrorDo errorDo = new QuSyncMesErrorDo();
        errorDo.setId(SecurityUtil.getUUID());
        errorDo.setErrordesc(errorDesc);
        errorDo.setMestablename(QUA_TABLE_NAME);
        errorDo.setMesid(id);
        return errorDo;
    }

    /**
     * 根据报废机台号 获取对应的组织机构
     *
     * @param organizationDoList
     * @param roptionCode
     * @return
     */
    private List<SysOrganizationDo> getOrgInfoByRoptionCode(List<SysOrganizationDo> organizationDoList, String roptionCode) {
        List<SysOrganizationDo> organizationDos = organizationDoList.stream().filter(info -> org.apache.commons.lang.StringUtils.isNotBlank(info.getRoption()) &&
                        Arrays.asList(((String) JSON.parseObject(info.getRoption(), HashMap.class).getOrDefault("code", "")).toLowerCase(Locale.ROOT).split(",")).contains(roptionCode.toLowerCase(Locale.ROOT)))
                .collect(Collectors.toList());
        return organizationDos;
    }
}
