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

import cn.estsh.i3plus.ext.mes.api.base.jx.IJxTimeSegmentStatisticsService;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesTimeSegmentStatistics;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesTimeSegmentStatisticsRepository;
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.platform.common.tool.TimeTool;
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.base.enumutil.MesEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.WmsEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @Description : 分时段统计方式实现
 * @Reference :
 * @Author : jiaqi.hou
 * @CreateDate : 2023/02/06 13:42
 * @Modify:
 **/
@Service
public class JxTimeSegmentStatisticsService implements IJxTimeSegmentStatisticsService {

    @Autowired
    private MesTimeSegmentStatisticsRepository timeSegmentStatisticsRDao;

    @Autowired
    private EntityManager entityManager;

    @Override
    public void insert(MesTimeSegmentStatistics statistics, String organizeCode, String userName){
        statistics.setOrganizeCode(organizeCode);
        //同一班次+开始时间+结束时间范围不允许有重叠的 ！
        validateExists(statistics);

        //如果休息时间不为空 获取休息消耗的时间 计算出时间长度 单位为分钟
        if (!StringUtils.isEmpty(statistics.getRestTime())){
            //休息时间需要在开始时间和结束时间之内（包含开始时间和结束时间）
            if (whetherTheTargetTimeIsWithinTheCurrentTime(statistics.getStartTime()+"-"+statistics.getEndTime(),statistics.getRestTime())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                        .setErrorDetail("休息时间【%s】必须在开始时间【%s】和结束时间【%s】内",
                                statistics.getRestTime(),statistics.getStartTime(),statistics.getEndTime())
                        .setErrorSolution("请重新操作！")
                        .build();
            }
            //休息的时间（分钟）
            long restTimeMin = getDatePoor(statistics.getRestTime());

            //总耗时
            long sumTime = getDatePoor(statistics.getStartTime()+"-"+statistics.getEndTime());

            //实际工作时长 = 总耗时 - 休息时间
            statistics.setTimeLength((sumTime - restTimeMin)+"");
        }else{
            //总耗时
            long sumTime = getDatePoor(statistics.getStartTime()+"-"+statistics.getEndTime());
            statistics.setTimeLength(sumTime+"");
        }
        statistics.setTimeSegmentCode(statistics.getShiftCode()+statistics.getStartTime());
        statistics.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelInitialize(statistics, userName);
        timeSegmentStatisticsRDao.insert(statistics);
    }

    @Override
    public void deleteByIds(Long[] ids, String userName) {
        DdlPackBean hql = new DdlPackBean();
        DdlPreparedPack.getInPackList(Arrays.asList(ids), "id", hql);
        int count = timeSegmentStatisticsRDao.findByHqlWhereCount(hql);
        if (count != ids.length){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("请检查数据是否全部有效")
                    .setErrorSolution("请重新操作！")
                    .build();
        }
        timeSegmentStatisticsRDao.deleteByIds(ids);
    }

    @Override
    public void update(MesTimeSegmentStatistics statistics, String organizeCode, String userName){
        //同一班次+开始时间+结束时间范围不允许有重叠的 ！
        statistics.setOrganizeCode(organizeCode);
        validateExists(statistics);

        //如果休息时间不为空 获取休息消耗的时间 计算出时间长度 单位为分钟
        if (!StringUtils.isEmpty(statistics.getRestTime())){
            //休息时间需要在开始时间和结束时间之内（包含开始时间和结束时间）
            if (whetherTheTargetTimeIsWithinTheCurrentTime(statistics.getStartTime()+"-"+statistics.getEndTime(),statistics.getRestTime())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                        .setErrorDetail("休息时间【%s】必须在开始时间【%s】和结束时间【%s】内",
                                statistics.getRestTime(),statistics.getStartTime(),statistics.getEndTime())
                        .setErrorSolution("请重新操作！")
                        .build();
            }
            //休息的时间（分钟）
            long restTimeMin = getDatePoor(statistics.getRestTime());

            //总耗时
            long sumTime = getDatePoor(statistics.getStartTime()+"-"+statistics.getEndTime());

            //实际工作时长 = 总耗时 - 休息时间
            statistics.setTimeLength((sumTime - restTimeMin)+"");
        }else{
            //总耗时
            long sumTime = getDatePoor(statistics.getStartTime()+"-"+statistics.getEndTime());
            statistics.setTimeLength(sumTime+"");
        }
        statistics.setTimeSegmentCode(statistics.getShiftCode()+statistics.getStartTime());
        statistics.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelUpdate(statistics, userName);
        timeSegmentStatisticsRDao.update(statistics);
    }

    @Override
    public void doDisable(Long[] ids, String userName) {
        DdlPackBean hql = new DdlPackBean();
        DdlPreparedPack.getInPackList(Arrays.asList(ids), "id", hql);
        int count = timeSegmentStatisticsRDao.findByHqlWhereCount(hql);
        if (count != ids.length){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("请检查数据是否全部有效")
                    .setErrorSolution("请重新操作！")
                    .build();
        }
        for (Long id : ids) {
            timeSegmentStatisticsRDao.updateByProperties(
                    new String[]{"id"},
                    new Object[]{id},
                    new String[]{"isValid", "modifyUser", "modifyDatetime", MesExtConstWords.SYSTEM_SYNC_STATUS},
                    new Object[]{WmsEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), userName, TimeTool.getNowTime(true), MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue()}
            );
        }
    }

    @Override
    public void doEnable(Long[] ids, String organizeCode, String userName) {
        DdlPackBean hql = new DdlPackBean();
        DdlPreparedPack.getInPackList(Arrays.asList(ids), "id", hql);
        int count = timeSegmentStatisticsRDao.findByHqlWhereCount(hql);
        if (count != ids.length){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("请检查数据是否全部有效")
                    .setErrorSolution("请重新操作！")
                    .build();
        }
        List<MesTimeSegmentStatistics> seasonInformationList = timeSegmentStatisticsRDao.findByHqlWhere(hql);
        for (MesTimeSegmentStatistics statistics : seasonInformationList) {
            validateExists(statistics);

            statistics.setIsValid(MesEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            statistics.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(statistics,userName);
            timeSegmentStatisticsRDao.update(statistics);
        }
    }

    @Override
    public ListPager<MesTimeSegmentStatistics> queryByPager(MesTimeSegmentStatistics partCheck, Pager pager) {
        DdlPackBean hql = new DdlPackBean();
        DdlPreparedPack.getNumEqualPack(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), "isDeleted", hql);
        DdlPreparedPack.getStringEqualPack(partCheck.getOrganizeCode(), "organizeCode", hql);
        DdlPreparedPack.getStringEqualPack(partCheck.getShiftCode(), "shiftCode", hql);
        DdlPreparedPack.getStringEqualPack(partCheck.getWorkCenterCode(), "workCenterCode", hql);
        DdlPreparedPack.getStringEqualPack(partCheck.getStartTime(), "startTime", hql);
        DdlPreparedPack.getStringEqualPack(partCheck.getEndTime(), "endTime", hql);
        DdlPreparedPack.getNumEqualPack(partCheck.getIsValid(), "isValid", hql);
        int count = timeSegmentStatisticsRDao.findByHqlWhereCount(hql);
        if (count>0){
            pager = PagerHelper.getPager(pager,count);
            List<MesTimeSegmentStatistics> partCheckList = timeSegmentStatisticsRDao.findByHqlPage(hql, pager);
            return new ListPager<>(partCheckList,pager);
        }
        return new ListPager<>(new ArrayList<>(),pager);
    }

    void validateExists(MesTimeSegmentStatistics statistics) {
        StringBuffer sbf = new StringBuffer("select statistics from MesTimeSegmentStatistics statistics where 1=1");
        sbf.append(" and (");
        sbf.append("(statistics.startTime<=:startTime and statistics.endTime>=:startTime)");//开始时间在两者之中
        sbf.append(" or ");
        sbf.append(" (statistics.startTime<=:endTime and statistics.endTime>=:endTime) ");//结束时间在两者之中
        sbf.append(" or ");
        sbf.append(" (statistics.startTime>=:startTime and statistics.endTime<=:endTime) ");// 结束时间开始时间之外
        sbf.append(" or ");
        sbf.append(" (statistics.startTime=:startTime and statistics.endTime=:endTime) ");// 结束时间开始时间之外
        sbf.append(")");
        sbf.append(" and statistics.shiftCode=:shiftCode");
        sbf.append(" and statistics.workCenterCode=:workCenterCode");
        sbf.append(" and statistics.organizeCode=:organizeCode");
        sbf.append(" and statistics.isValid=:isValid");
        sbf.append(" and statistics.isDeleted=:isDeleted");
        if (statistics.getId() != null) {
            sbf.append(" and statistics.id !=:id");
        }
        Query query = entityManager.createQuery(sbf.toString(), MesTimeSegmentStatistics.class);
        query.setParameter("organizeCode", statistics.getOrganizeCode());
        query.setParameter("isDeleted", CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        query.setParameter("isValid", CommonEnumUtil.IS_VAILD.VAILD.getValue());
        query.setParameter("startTime", statistics.getStartTime());
        query.setParameter("endTime", statistics.getEndTime());
        query.setParameter("shiftCode", statistics.getShiftCode());
        query.setParameter("workCenterCode", statistics.getWorkCenterCode());
        if (statistics.getId() != null) {
            query.setParameter("id", statistics.getId());
        }
        List<MesTimeSegmentStatistics> segmentStatisticsList = query.setMaxResults(1).getResultList();
        if (!CollectionUtils.isEmpty(segmentStatisticsList)) {
            MesTimeSegmentStatistics segmentStatistics = segmentStatisticsList.get(0);
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("已存在班次【%s】开始时间【%s】,结束时间【%s】不可交叉维护",
                            segmentStatistics.getShiftCode(),
                            segmentStatistics.getStartTime(),
                            segmentStatistics.getEndTime())
                    .setErrorSolution("请重新操作")
                    .build();
        }
    }
    public static long getDatePoor(String time){
        Date date;
        Date date2;
        try {
            String[] split = time.split("-");
            SimpleDateFormat df = new SimpleDateFormat("HH:mm");//设置日期格式
            date =df.parse(split[0]);
            date2 =df.parse(split[1]);
        }catch (Exception e){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("时间格式不正确，应该为【mm:ss-mm:ss】！")
                    .setErrorSolution("请重新操作")
                    .build();
        }
        // 获得两个时间的毫秒时间差异
        long diff = date2.getTime() - date.getTime();

        // 计算差多少分钟
        return (diff/1000/60);
    }

    public static boolean whetherTheTargetTimeIsWithinTheCurrentTime(String currentTime,String targetTime){
        Date currentTime1;
        Date currentTime2;
        Date targetTime1;
        Date targetTime2;
        try {
            String[] currentTimeSplit = currentTime.split("-");
            String[] targetTimeSplit = targetTime.split("-");
            SimpleDateFormat df = new SimpleDateFormat("HH:mm");//设置日期格式
            currentTime1 =df.parse(currentTimeSplit[0]);
            currentTime2 =df.parse(currentTimeSplit[1]);
            targetTime1 = df.parse(targetTimeSplit[0]);;
            targetTime2 = df.parse(targetTimeSplit[1]);;
        }catch (Exception e){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("时间格式不正确，应该为【mm:ss-mm:ss】！")
                    .setErrorSolution("请重新操作")
                    .build();
        }
        if ((currentTime1.before(targetTime1)&&currentTime1.before(targetTime2) &&
                targetTime1.before(currentTime2)&&targetTime2.before(currentTime2))
                || (currentTime1.compareTo(targetTime1)==0 &&
                (currentTime2.compareTo(targetTime2)==0 || currentTime2.compareTo(targetTime2)>0))) {
            return false;
        }
        return true;
    }
}
