package com.bs.mes.workorder;

import cn.hutool.core.date.DateUtil;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.vo.proWorkOrder.ArrangeRuleDto;
import com.ximai.mes.pro.domain.vo.proWorkOrder.WorkOrderArrangeResult;
import com.ximai.mes.pro.service.impl.ProArrangeServiceImpl;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;

/**
 * @ Author: chicheng.li
 * @ Date  : 2024/3/28
 */
public class ProArrangeServiceImplTest {

    @Test
    public void arrangeExecuteImpl() throws Exception {
        ProArrangeServiceImpl proWorkorderService = new ProArrangeServiceImpl();

        Method methods = ProArrangeServiceImpl.class.getDeclaredMethod("arrangeExecute", List.class, Map.class, List.class);
        methods.setAccessible(true);
        List<ProWorkorder> workorderList = new ArrayList<>();
        Map<String, ArrangeRuleDto> ruleMap = new HashMap<>();
        List<Map<String, Object>> arrangeRuleVals = new ArrayList<>();
        WorkOrderArrangeResult result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        Assert.assertEquals(result.getArrangeList().size(), 0);
        Assert.assertEquals(result.getUnArrangeList().size(), 0);

        //1.单工序+单属性值满足/不满足编排规则
        ruleMap.clear();
        workorderList.clear();
        arrangeRuleVals.clear();
        ruleMap.put("测试分类测试工序", new ArrangeRuleDto(Arrays.asList("v1")));
        ruleMap.put("测试分类测试工序2", new ArrangeRuleDto(Arrays.asList("v1")));
        for (int i = 0; i < 100; i++) {
            ProWorkorder temp = ProWorkorder.builder().workorderId(Long.valueOf(i))
                    .build();
            workorderList.add(temp);
            int[] tempI = new int[]{i};
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    if (tempI[0] % 5 == 2) {
                        put("process_name", "测试工序11");
                    } else {
                        put("process_name", "测试工序");
                    }
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    //属性值
                    put("v1", "1");
                }
            });
        }
        result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        //80编排成功，20由于未配置编排规则失败
        Assert.assertEquals(result.getArrangeList().size(), 1);
        Assert.assertEquals(result.getArrangeList().get(0).size(), 80);
        Assert.assertEquals(result.getUnArrangeList().size(), 20);

        //2。单工序+单属性值匹配编排规则
        ruleMap.clear();
        workorderList.clear();
        arrangeRuleVals.clear();
        ruleMap.put("测试分类测试工序", new ArrangeRuleDto(Arrays.asList("v1")));
        ruleMap.put("测试分类测试工序2", new ArrangeRuleDto(Arrays.asList("v1")));
        ruleMap.put("测试分类测试工序3", new ArrangeRuleDto(Arrays.asList("v1")));
        for (int i = 0; i < 100; i++) {
            ProWorkorder temp = ProWorkorder.builder().workorderId(Long.valueOf(i))
                    .build();
            workorderList.add(temp);
            int[] tempI = new int[]{i};
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    //属性值
                    put("v1", "1");
                }
            });
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序2");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    //属性值
                    if (tempI[0] % 4 == 0) {
                        put("v1", new Random().nextDouble());
                    } else {
                        put("v1", "1");
                    }
                }
            });

            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序11");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    //属性值
                    put("v1", "1");
                }
            });
        }
        result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        //75编排成功，25由于工序2属性值不一致未匹配
        Assert.assertEquals(result.getArrangeList().size(), 1);
        Assert.assertEquals(result.getArrangeList().get(0).size(), 75);
        Assert.assertEquals(result.getUnArrangeList().size(), 25);

        //4.单工序+多属性值区配编排规则
        ruleMap.clear();
        workorderList.clear();
        arrangeRuleVals.clear();
        ruleMap.put("测试分类测试工序", new ArrangeRuleDto(Arrays.asList("v1", "v2")));
        for (int i = 0; i < 100; i++) {
            ProWorkorder temp = ProWorkorder.builder().workorderId(Long.valueOf(i))
                    .build();
            workorderList.add(temp);
            int[] tempI = new int[]{i};
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    //属性值1
                    put("v1", "1");
                    //属性2,1/4相等
                    put("v2", (tempI[0] % 4) + "");
                }
            });
        }
        result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        //全部编排成功，v2 1/4相等，所以分了4组
        Assert.assertEquals(result.getArrangeList().size(), 4);
        Assert.assertEquals(result.getArrangeList().get(0).size(), 25);
        Assert.assertEquals(result.getArrangeList().get(1).size(), 25);
        Assert.assertEquals(result.getArrangeList().get(2).size(), 25);
        Assert.assertEquals(result.getArrangeList().get(3).size(), 25);
        Assert.assertEquals(result.getUnArrangeList().size(), 0);

        //5.多工序+单属性值匹配编排规则
        ruleMap.clear();
        workorderList.clear();
        arrangeRuleVals.clear();
        ruleMap.put("测试分类测试工序", new ArrangeRuleDto(Arrays.asList("v1", "v2")));
        ruleMap.put("测试分类测试工序2", new ArrangeRuleDto(Arrays.asList("v1", "v2")));
        ruleMap.put("测试分类测试工序3", new ArrangeRuleDto(Arrays.asList("v1", "v2", "v3")));
        for (int i = 0; i < 100; i++) {
            ProWorkorder temp = ProWorkorder.builder().workorderId(Long.valueOf(i))
                    .build();
            workorderList.add(temp);
            int[] tempI = new int[]{i};
            //满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] % 4 + "");
                }
            });
            //满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序2");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] % 5 + "");
                }
            });
            //不满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序10");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] + "");
                }
            });
            //不满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序11");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] + "");
                }
            });
        }
        result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        //4、5的公约数为20，共分20组，每组5个
        Assert.assertEquals(result.getArrangeList().size(), 20);
        Assert.assertEquals(result.getArrangeList().get(0).size(), 5);
        Assert.assertEquals(result.getArrangeList().get(1).size(), 5);
        Assert.assertEquals(result.getArrangeList().get(2).size(), 5);
        Assert.assertEquals(result.getArrangeList().get(3).size(), 5);
        Assert.assertEquals(result.getUnArrangeList().size(), 0);

        //6.多工序+多属性值匹配编排规则
        ruleMap.clear();
        workorderList.clear();
        arrangeRuleVals.clear();
        ruleMap.put("测试分类测试工序", new ArrangeRuleDto(Arrays.asList("v1", "v2")));
        ruleMap.put("测试分类测试工序2", new ArrangeRuleDto(Arrays.asList("v1", "v2")));
        ruleMap.put("测试分类测试工序3", new ArrangeRuleDto(Arrays.asList("v1", "v2", "v3")));
        for (int i = 0; i < 100; i++) {
            ProWorkorder temp = ProWorkorder.builder().workorderId(Long.valueOf(i))
                    .build();
            workorderList.add(temp);
            int[] tempI = new int[]{i};
            //满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] % 4 + "");
                    put("v2", tempI[0] % 4 + "");
                }
            });
            //满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序2");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] % 4 + "");
                    //20条数据不一致
                    if (tempI[0] % 5 == 0) {
                        put("v2", new Random().nextDouble() + "");
                    } else {
                        put("v2", tempI[0] % 4 + "");
                    }
                }
            });
            //不满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序10");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] + "");
                }
            });
            //不满足匹配规则
            arrangeRuleVals.add(new HashMap<String, Object>() {
                {
                    put("process_name", "测试工序11");
                    put("item_type_name", "测试分类");
                    put("workorder_id", Long.valueOf(tempI[0]));
                    put("v1", tempI[0] + "");
                }
            });
        }
        result = (WorkOrderArrangeResult) methods.invoke(proWorkorderService, workorderList, ruleMap, arrangeRuleVals);
        //80编排成功，v2 第2道序20条不一致
        Assert.assertEquals(result.getArrangeList().size(), 4);
        Assert.assertEquals(result.getArrangeList().get(0).size(), 20);
        Assert.assertEquals(result.getArrangeList().get(1).size(), 20);
        Assert.assertEquals(result.getArrangeList().get(2).size(), 20);
        Assert.assertEquals(result.getArrangeList().get(3).size(), 20);
        Assert.assertEquals(result.getUnArrangeList().size(), 20);
    }


    @Test
    public void deliveryIntervalExecuteImpl() throws Exception {
        ProArrangeServiceImpl proWorkorderService = new ProArrangeServiceImpl();
        Method methods = ProArrangeServiceImpl.class.getDeclaredMethod("deliveryIntervalExecute", List.class, Integer.class, Integer.class);
        methods.setAccessible(true);
        List<ProWorkorder> workorderList = new ArrayList<>();
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-02"));
            setQuantity(new BigDecimal("1000"));
            setWorkorderId(1L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-02"));
            setQuantity(new BigDecimal("500"));
            setWorkorderId(2L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-08"));
            setQuantity(new BigDecimal("2000"));
            setWorkorderId(3L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-12"));
            setQuantity(new BigDecimal("1500"));
            setWorkorderId(4L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-13"));
            setQuantity(new BigDecimal("800"));
            setWorkorderId(5L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-21"));
            setQuantity(new BigDecimal("900"));
            setWorkorderId(6L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-22"));
            setQuantity(new BigDecimal("1100"));
            setWorkorderId(7L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-25"));
            setQuantity(new BigDecimal("1200"));
            setWorkorderId(8L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-06-28"));
            setQuantity(new BigDecimal("1000"));
            setWorkorderId(9L);
        }});
        workorderList.add(new ProWorkorder() {{
            setRequestDate(DateUtil.parseDate("2024-07-02"));
            setQuantity(new BigDecimal("900"));
            setWorkorderId(10L);
        }});
        List<List<ProWorkorder>> result = (List<List<ProWorkorder>>) methods.invoke(proWorkorderService, workorderList, 7, 1000);
        Assert.assertEquals(3, result.size());
        Assert.assertEquals(6, result.get(0).size());
        Assert.assertArrayEquals(new Long[]{1L, 3L, 2L, 5L, 6L, 10L}, result.get(0).stream().map(s -> s.getWorkorderId()).toArray());
        Assert.assertEquals(1, result.get(1).size());
        Assert.assertArrayEquals(new Long[]{4L}, result.get(1).stream().map(s -> s.getWorkorderId()).toArray());
        Assert.assertEquals(3, result.get(2).size());
        Assert.assertArrayEquals(new Long[]{7L, 8L, 9L}, result.get(2).stream().map(s -> s.getWorkorderId()).toArray());
        //不存在最小数量
        result = (List<List<ProWorkorder>>) methods.invoke(proWorkorderService, workorderList, 7, null);
        Assert.assertEquals(4, result.size());
        Assert.assertEquals(3, result.get(0).size());
        Assert.assertEquals(2, result.get(1).size());
        Assert.assertEquals(3, result.get(2).size());
        Assert.assertEquals(2, result.get(3).size());
        //不存在配置，未分组
        result = (List<List<ProWorkorder>>) methods.invoke(proWorkorderService, workorderList, 0, null);
        Assert.assertEquals(1, result.size());
        Assert.assertEquals(10, result.get(0).size());


    }

}