package com.bs.mes.schedule.strategy;

import com.ximai.mes.pro.schedule.Equipment;
import com.ximai.mes.pro.schedule.IOperationTimeCalculator;
import com.ximai.mes.pro.schedule.Job;
import com.ximai.mes.pro.schedule.TaskSchedulingContext;
import com.ximai.mes.pro.schedule.strategy.EvaluateEquipmentDeliveryTime;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public class EvaluateEquipmentDeliveryTimeTest {
    @Test
    public void evaluate() {
        EvaluateEquipmentDeliveryTime evaluateEquipmentDeliveryTime = new EvaluateEquipmentDeliveryTime();
        TaskSchedulingContext context = new TaskSchedulingContext();
        IOperationTimeCalculator.OperationTimePlan operationTimePlan = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan.setPlan(operationTimePlanItemList);
        operationTimePlan.setScheduledSuccess(true);
        operationTimePlanItemList.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2888));
            setEndedTime(Duration.ofMinutes(2898));
            setShiftType("白班");
        }});
        Job job = new Job("1", Duration.ofMinutes(12));
        job.setProducedDeliveryTime(Duration.ofMinutes(3000));
        context.setJob(job);
        List<TaskSchedulingContext.TaskSchedulingResultContext> scheduleResult = new ArrayList<>();
        Equipment equipment1 = new Equipment();
        equipment1.setId(1L);
        context.setEquipment(equipment1);
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment1, operationTimePlan, context));
        //设备在交期范围内的加工
        double rst = evaluateEquipmentDeliveryTime.evaluate(context, operationTimePlan, scheduleResult);
        Assert.assertEquals(10, rst, Double.valueOf(0.0));
        //设备在交期范围外的加工
        operationTimePlanItemList.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(3000));
            setEndedTime(Duration.ofMinutes(3002));
            setShiftType("白班");
        }});
        rst = evaluateEquipmentDeliveryTime.evaluate(context, operationTimePlan, scheduleResult);
        Assert.assertEquals(5, rst, Double.valueOf(0.001));
        //我设备可选情况
        Equipment equipment2 = new Equipment();
        equipment2.setId(2L);
        IOperationTimeCalculator.OperationTimePlan operationTimePlan2 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList2 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan2.setPlan(operationTimePlanItemList2);
        operationTimePlan2.setScheduledSuccess(true);
        operationTimePlanItemList2.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2888));
            setEndedTime(Duration.ofMinutes(3898));
            setShiftType("白班");
        }});
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment2, operationTimePlan2, context));
        Equipment equipment3 = new Equipment();

        IOperationTimeCalculator.OperationTimePlan operationTimePlan3 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList3 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan3.setPlan(operationTimePlanItemList3);
        operationTimePlan3.setScheduledSuccess(true);
        operationTimePlanItemList3.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2588));
            setEndedTime(Duration.ofMinutes(2598));
            setShiftType("白班");
        }});
        equipment3.setId(3L);
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment3, operationTimePlan3, context));

        operationTimePlanItemList.get(1).setShiftType("中班");
        rst = evaluateEquipmentDeliveryTime.evaluate(context, operationTimePlan, scheduleResult);
        Assert.assertEquals(4, rst, Double.valueOf(0.001));

        //开始时间评分相同的数据
        scheduleResult.clear();
        IOperationTimeCalculator.OperationTimePlan operationTimePlan4 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList4 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan4.setPlan(operationTimePlanItemList4);
        operationTimePlan4.setScheduledSuccess(true);
        operationTimePlanItemList4.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2588));
            setEndedTime(Duration.ofMinutes(2598));
            setShiftType("白班");
        }});
        operationTimePlanItemList4.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2600));
            setEndedTime(Duration.ofMinutes(2650));
            setShiftType("白班");
        }});
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment3, operationTimePlan3, context));
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment2, operationTimePlan4, context));

        rst = evaluateEquipmentDeliveryTime.evaluate(context, operationTimePlan3, scheduleResult);
        Assert.assertEquals(10, rst, Double.valueOf(0.001));

    }

    @Test
    public void getRank() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        EvaluateEquipmentDeliveryTime evaluateEquipmentDeliveryTime = new EvaluateEquipmentDeliveryTime();
        Method methods = EvaluateEquipmentDeliveryTime.class.getDeclaredMethod("getRank", Equipment.class, List.class);
        methods.setAccessible(true);
        Equipment equipment1 = new Equipment();
        equipment1.setId(1L);
        Equipment equipment2 = new Equipment();
        equipment2.setId(2L);
        Equipment equipment3 = new Equipment();
        equipment3.setId(3L);
        Equipment equipment4 = new Equipment();
        equipment4.setId(4L);

        List<TaskSchedulingContext.TaskSchedulingResultContext> scheduleResult = new ArrayList<>();
        IOperationTimeCalculator.OperationTimePlan operationTimePlan = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan.setPlan(operationTimePlanItemList);
        operationTimePlan.setScheduledSuccess(true);
        operationTimePlanItemList.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2888));
            setEndedTime(Duration.ofMinutes(2898));
            setShiftType("白班");
        }});
        operationTimePlanItemList.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(3000));
            setEndedTime(Duration.ofMinutes(3002));
            setShiftType("白班");
        }});

        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment1, operationTimePlan, null));

        IOperationTimeCalculator.OperationTimePlan operationTimePlan3 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList3 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan3.setPlan(operationTimePlanItemList3);
        operationTimePlan3.setScheduledSuccess(true);
        operationTimePlanItemList3.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2588));
            setEndedTime(Duration.ofMinutes(2598));
            setShiftType("白班");
        }});
        operationTimePlanItemList3.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2600));
            setEndedTime(Duration.ofMinutes(2650));
            setShiftType("白班");
        }});

        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment2, operationTimePlan3, null));

        IOperationTimeCalculator.OperationTimePlan operationTimePlan2 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList2 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan2.setPlan(operationTimePlanItemList2);
        operationTimePlan2.setScheduledSuccess(true);
        operationTimePlanItemList2.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(2588));
            setEndedTime(Duration.ofMinutes(2598));
            setShiftType("白班");
        }});
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment3, operationTimePlan2, null));
        int rst = (int) methods.invoke(evaluateEquipmentDeliveryTime, equipment1, scheduleResult);
        Assert.assertEquals(2, rst);
        rst = (int) methods.invoke(evaluateEquipmentDeliveryTime, equipment2, scheduleResult);
        Assert.assertEquals(1, rst);
        rst = (int) methods.invoke(evaluateEquipmentDeliveryTime, equipment3, scheduleResult);
        Assert.assertEquals(1, rst);


        IOperationTimeCalculator.OperationTimePlan operationTimePlan4 = new IOperationTimeCalculator.OperationTimePlan();
        List<IOperationTimeCalculator.OperationTimePlanItem> operationTimePlanItemList4 = new ArrayList<IOperationTimeCalculator.OperationTimePlanItem>();
        operationTimePlan4.setPlan(operationTimePlanItemList4);
        operationTimePlan4.setScheduledSuccess(true);
        operationTimePlanItemList4.add(new IOperationTimeCalculator.OperationTimePlanItem() {{
            setStartedTime(Duration.ofMinutes(3200));
            setEndedTime(Duration.ofMinutes(3300));
            setShiftType("白班");
        }});
        scheduleResult.add(new TaskSchedulingContext.TaskSchedulingResultContext(equipment4, operationTimePlan4, null));
        rst = (int) methods.invoke(evaluateEquipmentDeliveryTime, equipment4, scheduleResult);
        Assert.assertEquals(3, rst);

    }
}
