package com.ximai.mes.pro.schedule.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ximai.common.exception.ServiceException;
import com.ximai.common.utils.MessageUtils;
import com.ximai.mes.cal.domain.CalPlanWorkunit;
import com.ximai.mes.cal.service.ICalPlanWorkunitService;
import com.ximai.mes.constant.ProcessControlCodeEnum;
import com.ximai.mes.md.service.IMdWorkunitService;
import com.ximai.mes.md.vo.MdWorkunitVo;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcess;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolution;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolutionProcess;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolutionSpecificationSheet;
import com.ximai.mes.pro.domain.task.ProTaskWorkunit;
import com.ximai.mes.pro.domain.task.WorkorderScheduleParams;
import com.ximai.mes.pro.domain.vo.ProProductionSolutionVo;
import com.ximai.mes.pro.schedule.*;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkOrderProcessService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.productionSolution.IProProductionSolutionProcessService;
import com.ximai.mes.pro.service.productionSolution.IProProductionSolutionService;
import com.ximai.mes.pro.service.productionSolution.IProProductionSolutionSpecificationSheetService;
import com.ximai.mes.pro.service.task.IProTaskWorkunitService;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 加载排产业务数据实现
 */
@Component
public class AlgorithmDataSourceImpl implements AlgorithmDataSource {

    @Autowired
    IMdWorkunitService mdWorkunitService;
    @Autowired
    ICalPlanWorkunitService calPlanWorkunitService;
    @Autowired
    IProWorkorderService proWorkorderService;
    @Autowired
    IProWorkOrderProcessService proWorkOrderProcessService;
    @Autowired
    IProTaskWorkunitService proTaskWorkunitService;
    @Autowired
    IProProductionSolutionService proProductionSolutionService;
    @Autowired
    IProProductionSolutionProcessService proProductionSolutionProcessService;
    @Autowired
    IProProductionSolutionSpecificationSheetService proProductionSolutionSpecificationSheetService;

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        QueryWrapper<MdWorkunitVo> query = new QueryWrapper<MdWorkunitVo>();
        query.eq("t1.enable_flag", "Y");
        query.isNotNull("t1.workstation_id");
        List<Equipment> algEquipments = new ArrayList<Equipment>();
        List<MdWorkunitVo> workunitList = mdWorkunitService.selectMdWorkunitJoinWorkstation(query);
        //查询作业单元
        for (MdWorkunitVo workUnit : workunitList) {
            Equipment equipment = new Equipment() {{
                setId(workUnit.getWorkunitId());
                setWorkUnitCode(workUnit.getWorkunitCode());
                setWorkUnitName(workUnit.getWorkunitName());
                setWorkCenterId(workUnit.getWorkstationId());
                setWorkCenterCode(workUnit.getWorkstationCode());
                setWorkCenterName(workUnit.getWorkstationName());
                if(workUnit.getTransferTime()!=null){
                    setTransferShopTime(workUnit.getTransferTime().intValue());
                }
                if(workUnit.getSolidifyTime()!=null){
                    setCuringTime(workUnit.getSolidifyTime().intValue());
                }
                setIsParallel(false);
            }};
            equipment.initEquipmentAttribute(workUnit);
            equipment.initEquipmentFunction(workUnit);
            algEquipments.add(equipment);
        }
        stopWatch.stop();
        logger.info(String.format("排产设备加载耗时：%s", stopWatch.getTotalTimeSeconds()));
        return algEquipments.stream().map(s -> (Resource) s).collect(Collectors.toList());
    }

    @Override
    public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {

        return null;
    }

    @Override
    public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Map<Long, Resource> resourceMap = resources.stream().collect(Collectors.toMap(s -> s.getId(), s -> s));
        List<Calendar> algCalendar = new ArrayList<Calendar>();
        QueryWrapper<CalPlanWorkunit> calPlanWorkunitQuery = new QueryWrapper<CalPlanWorkunit>();
        calPlanWorkunitQuery.eq("rest_flag", 0);
        calPlanWorkunitQuery.gt("start_date", schedulingStartedDate);
        calPlanWorkunitQuery.orderByAsc("start_date");
        //查询可用工作日历
        List<CalPlanWorkunit> list = calPlanWorkunitService.selectListWithSchedule(calPlanWorkunitQuery);
        for (CalPlanWorkunit etpCal : list) {
            if (!resourceMap.containsKey(etpCal.getWorkunitId())) {
                continue;
            }
            Calendar.WorkingCalendar alg_CalendarItem = new Calendar.WorkingCalendar() {{
                setStartedTime(Duration.between(schedulingStartedDate, DateUtil.toLocalDateTime(etpCal.getStartDate())));
                setEndedTime(Duration.between(schedulingStartedDate, DateUtil.toLocalDateTime(etpCal.getEndDate())));
                setResource(resourceMap.get(etpCal.getWorkunitId()));
                setStartedTime2(DateUtil.toLocalDateTime(etpCal.getStartDate()));
                setEndedTime2(DateUtil.toLocalDateTime(etpCal.getEndDate()));
                setShiftType(etpCal.getShiftType());
            }};
            alg_CalendarItem.getCalendarData().put("CalendarID", etpCal.getId());
            algCalendar.add(alg_CalendarItem);
        }
        //查询占用日历（已排产数据）
        QueryWrapper<ProTaskWorkunit> taskQuery = new QueryWrapper<ProTaskWorkunit>();
        taskQuery.ge("schedule_start_date", schedulingStartedDate);
        taskQuery.isNotNull("schedule_start_date");
        List<ProTaskWorkunit> taskWorkunits = proTaskWorkunitService.selectTaskWorkUnitJoinTask(taskQuery);
        taskWorkunits.forEach(s -> {
            Calendar.OccupiedCalendar alg_CalendarItem = new Calendar.OccupiedCalendar() {{
                setStartedTime(Duration.between(schedulingStartedDate, DateUtil.toLocalDateTime(s.getScheduleStartDate())));
                setEndedTime(Duration.between(schedulingStartedDate, DateUtil.toLocalDateTime(s.getScheduleEndDate())));
                setStartedTime2(DateUtil.toLocalDateTime(s.getScheduleStartDate()));
                setEndedTime2(DateUtil.toLocalDateTime(s.getScheduleEndDate()));
                setResource(resourceMap.get(s.getWorkunitId()));
            }};
            algCalendar.add(alg_CalendarItem);
        });
        stopWatch.stop();
        logger.info(String.format("排产日历数据加载耗时：%s", stopWatch.getTotalTimeSeconds()));
        return algCalendar;
    }

    //按编排单号分组的工单数据
    @Data
    public class ScheduleJobGroup {
        List<ProWorkorder> workorderList;
        //最近交期
        LocalDateTime demandDate;
        //总数量
        BigDecimal quantity;
        //工单单号
        String workorderCode;
    }

}
