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

import cn.hutool.core.date.StopWatch;
import com.ximai.common.exception.ServiceException;
import com.ximai.common.utils.MessageUtils;
import com.ximai.mes.constant.TaskStatusEnum;
import com.ximai.mes.constant.WorkorderStatusEnum;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.task.ProTask;
import com.ximai.mes.pro.domain.task.ProTaskWorkorder;
import com.ximai.mes.pro.domain.task.ProTaskWorkunit;
import com.ximai.mes.pro.schedule.AlgorithmResultProcess;
import com.ximai.mes.pro.schedule.Job;
import com.ximai.mes.pro.schedule.ScheduleStatus;
import com.ximai.mes.pro.schedule.Task;
import com.ximai.mes.pro.schedule.impl.busi.JobResult;
import com.ximai.mes.pro.schedule.impl.busi.ScheduleBusiProcess;
import com.ximai.mes.pro.schedule.impl.busi.TaskResult;
import com.ximai.mes.pro.service.IProMaterialRequestService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.task.IProTaskService;
import com.ximai.mes.pro.service.task.IProTaskWorkorderService;
import com.ximai.mes.pro.service.task.IProTaskWorkunitService;
import com.ximai.mes.tm.service.ITmToolRequestService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Component
public class AlgorithmResultProcessImpl implements AlgorithmResultProcess {
 
    @Autowired
    IProTaskService proTaskService;
    @Autowired
    IProTaskWorkunitService proTaskWorkunitService;
    @Autowired
    IProTaskWorkorderService proTaskWorkorderService;
    @Autowired
    IProWorkorderService proWorkorderService;
    @Autowired
    private ITmToolRequestService tmToolRequestService;

    @Autowired
    private IProMaterialRequestService proMaterialRequestService;

    @Resource
    List<ScheduleBusiProcess> busiProcesseList;

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

    @Transactional
    @Override
    public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<JobResult> jobResults = new ArrayList<>();
        for (Job job : jobs) {
            JobResult jobResult = new JobResult();
            jobResults.add(jobResult);
            List<TaskResult> taskResults = new ArrayList<>();
            jobResult.setTaskResultList(taskResults);
            jobResult.setQuantity(job.getQuantity());
            jobResult.setWorkorderList(job.getJobExtend().getWorkorderList());
            if (!ScheduleStatus.Success.equals(job.getScheduleStatus()) &&
                    !ScheduleStatus.Delay.equals(job.getScheduleStatus())) {
                throw new ServiceException(MessageUtils.message("pro.schedule.error.fail", job.getScheduleStatus()
                        .getDescription(), job.getId(), job.getScheduleDesc()));
            }
            int i = 1;
            for (Task task : job.getTasks()) {
                //保存任务表
                ProTask proTask = this.convertTask(job, task);
                proTask.setArrangeCode(job.getId());
                proTask.setTaskBatch(proTask.getArrangeCode()+"-" +
                        StringUtils.leftPad(job.getJobExtend().getWorkorderList().get(0).getBatchSerial()+"",3,"0"));
                proTask.setOrdinal(i);
                //首工序，待加工数等于排产数
                if (i == 1) {
                    proTask.setQuantityWait(task.getOrderQuantity());
                } else {
                    proTask.setQuantityWait(BigDecimal.ZERO);
                }
                //末道工序，打上标记
                if (i == job.getTasks().size()) {
                    proTask.setIsLastProcess(1);
                } else {
                    proTask.setIsLastProcess(0);
                }
                proTaskService.insertProTask(proTask);
                TaskResult taskResult = new TaskResult();
                taskResult.setProTask(proTask);
                taskResults.add(taskResult);
                long j = 1;
                for (ProWorkorder workorder : job.getJobExtend().getWorkorderList()) {
                    ProTaskWorkorder proTaskWorkorder = new ProTaskWorkorder();
                    proTaskWorkorder.setTaskId(proTask.getTaskId());
                    proTaskWorkorder.setIdx(j);
                    proTaskWorkorder.setWorkorderId(workorder.getWorkorderId());
                    // 保存
                    proTaskWorkorderService.insertProTaskWorkorder(proTaskWorkorder);
                    j++;
                }
                List<Long> taskWorkunitIds = new ArrayList<>();
                //保存派工数据
                List<Task> dispenseList = task.getSplitTask();
                List<ProTaskWorkunit> workunitList = new ArrayList<>();
                if (dispenseList == null) {
                    ProTaskWorkunit taskWorkunit = this.convertTaskWorkunit(scheduleStartDate, proTask, job, task);
                    proTaskWorkunitService.insertProTaskWorkunit(taskWorkunit);
                    taskWorkunitIds.add(taskWorkunit.getTaskWorkunitId());
                    workunitList.add(taskWorkunit);
                } else {
                    for (Task dispense : dispenseList) {
                        ProTaskWorkunit taskWorkunit = this.convertTaskWorkunit(scheduleStartDate, proTask, job, dispense);
                        proTaskWorkunitService.insertProTaskWorkunit(taskWorkunit);
                        taskWorkunitIds.add(taskWorkunit.getWorkunitId());
                        workunitList.add(taskWorkunit);
                    }
                }
                taskResult.setProTaskWorkunitList(workunitList);
                i++;
            }
        }
        busiProcesseList.forEach(s->{
            s.execute(jobResults);
        });
        stopWatch.stop();
        logger.info(String.format("排产结果保存、刀具/物料申请单生成耗时：%s", stopWatch.getTotalTimeSeconds()));

    }

    private ProTask convertTask(Job job, Task task) {
        ProTask proTask = new ProTask();
        proTask.setProcessId(task.getProcessId());
        proTask.setIdx(task.getIdx());
        proTask.setProcessName(task.getProcessName());
        proTask.setQuantity(task.getOrderQuantity());
        proTask.setWorkstationId(task.getScheduledEquipment().getWorkCenterId());
        proTask.setWorkstationCode(task.getScheduledEquipment().getWorkCenterCode());
        proTask.setWorkstationName(task.getScheduledEquipment().getWorkCenterName());
        return proTask;
    }

    private ProTaskWorkunit convertTaskWorkunit(LocalDateTime scheduleStartDate, ProTask proTask, Job job, Task task) {
        ProTaskWorkunit taskWorkunit = new ProTaskWorkunit();
        taskWorkunit.setTaskId(proTask.getTaskId());
        taskWorkunit.setIdx(1L);
        taskWorkunit.setWorkunitId(task.getScheduledEquipment().getId());
        taskWorkunit.setWorkunitCode(task.getScheduledEquipment().getWorkUnitCode());
        taskWorkunit.setWorkunitName(task.getScheduledEquipment().getWorkUnitName());
        taskWorkunit.setQuantity(task.getOrderQuantity());
        taskWorkunit.setQuantityProduced(BigDecimal.ZERO);
        taskWorkunit.setQuantityQualify(BigDecimal.ZERO);
        taskWorkunit.setQuantityUnqualify(BigDecimal.ZERO);
        taskWorkunit.setStatus(TaskStatusEnum.PREPARE.getStatus());
        taskWorkunit.setOutsourced(0);
        taskWorkunit.setUnitPrice(task.getUnitPrice());
        taskWorkunit.setStdWorkingTime(task.getStdWorkingTime());
        taskWorkunit.setStdWorkingTimeUom(task.getStdWorkingTimeUom());
        LocalDateTime sdate = job.getScheduleDate().plus(task.getScheduledStartedTime());
        LocalDateTime edate = job.getScheduleDate().plus(task.getScheduledEndedTime());
        Date sdate1 = Date.from(sdate.atZone(ZoneId.systemDefault()).toInstant());
        Date edate1 = Date.from(edate.atZone(ZoneId.systemDefault()).toInstant());
        taskWorkunit.setScheduleStartDate(sdate1);
        taskWorkunit.setScheduleEndDate(edate1);
        return taskWorkunit;
    }

}
