
package com.clx.performance.service.impl;

import com.clx.message.feign.ClxMessageOpenapiFeign;
import com.clx.performance.config.ClxMessageConfig;
import com.clx.performance.config.LoadAppConfig;
import com.clx.performance.constant.RedisConstants;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dto.gd.GdRouteDTO;
import com.clx.performance.dto.zjxl.TruckTraceDTO;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.model.App;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.service.DriverNoticeConfigService;
import com.clx.performance.utils.gd.GdService;
import com.clx.performance.vo.pc.DriverNoticeConfigVO;
import com.msl.common.base.Optional;
import com.msl.common.open.OpenClient;
import com.msl.common.result.Result;
import com.purchase.manage.dto.SupervisionLoadInfoDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.math.BigDecimal;
import java.util.*;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class OrderChildServiceImpl2Test {

    @Mock
    private RedisTemplate redisTemplate;
    @Mock
    private OrderGoodsDao orderGoodsDao;
    @Mock
    private HashOperations<String, String, TruckTraceDTO> hashOps;

    @Mock
    private DriverNoticeConfigService driverNoticeConfigService;

    @InjectMocks
    private OrderChildServiceImpl orderChildService;

    @Mock
    private OrderChildDao orderChildDao;

    @Mock
    private GdService gdService;
    @Mock
    private ClxMessageConfig messageConfig;
    @Mock
    private ClxMessageOpenapiFeign clxMessageOpenapiFeign;
    @Mock
    private LoadAppConfig appConfig;


    @BeforeEach
    void setUp() {
        // Setup common mock interactions here if any
    }

    @Test
    void testOrderChildMessageNotice() {
        orderChildService.orderChildMessageNotice();
    }


    @Test
    void testOrderChildMessageNoticeListConfigDisabled() {
        // Arrange
        DriverNoticeConfigVO configVO = new DriverNoticeConfigVO();
        configVO.setStatus(0);
        configVO.setNoticeTriggerDistance(BigDecimal.valueOf(5000));
        when(driverNoticeConfigService.listConfig()).thenReturn(configVO);

        orderChildService.orderChildMessageNotice();
    }

    /**
     * 状态为到达货源地，超出范围，发短信，修改状态，修改已发短信状态
     */
    @Test
    void testOrderChildMessageNoticeListConfigEnabled() {
        //模拟两个运单
        List<OrderChild> mockOrderChildList = new ArrayList<>();
        OrderChild child1 = new OrderChild();
        child1.setChildNo("childNo1");
        child1.setOrderGoodsNo("orderGoods1");
        child1.setTruckNo("truckNo1");
        child1.setRemoveLoadLimitStatus(0);
        child1.setExitNoticeStatus(0);
        //到达货源地
        child1.setStatus(OrderChildEnum.Status.ARRIVE_SEND.getCode());
        child1.setDriverMobile("12345678901");
        mockOrderChildList.add(child1);
        when(orderChildDao.listOrderChild(anyList(), any(), any())).thenReturn(mockOrderChildList);

        Map<String, TruckTraceDTO> truckTraceMap = new HashMap<>();
        TruckTraceDTO truckTraceDTO = new TruckTraceDTO();
        truckTraceDTO.setLocation(new BigDecimal[]{BigDecimal.ONE, BigDecimal.TEN});
        truckTraceDTO.setTruckNo("truckNo1");
        truckTraceMap.put("truckNo1", truckTraceDTO);

        when(redisTemplate.opsForHash()).thenReturn(hashOps);
        when(hashOps.entries(RedisConstants.ZJXL_TRUCK_TRACE_LIST)).thenReturn(truckTraceMap);

        OrderGoods orderGoods = new OrderGoods();

        //货单
        when(orderGoodsDao.getByOrderGoodsNo(child1.getOrderGoodsNo())).thenReturn(Optional.of(orderGoods));
        when(driverNoticeConfigService.listConfig()).thenReturn(mockDriverNoticeConfigVO());


        // gdRoute
        GdRouteDTO gdRoute = new GdRouteDTO();
        //设置3000 ，超出提醒范围了
        gdRoute.setDistance(3000);
        // 假设高德服务返回了一个有效的路线
        Mockito.when(gdService.getRoute(any(), any(), any(), any())).thenReturn(Collections.singletonList(gdRoute));


        // 调用方法
        orderChildService.orderChildMessageNotice();

        //验证运单状态
        assertEquals(child1.getEnterExitSendStatus(), OrderChildEnum.EnterExitSendStatus.DRIVE_OUT.getCode());
        assertEquals(child1.getExitNoticeStatus(), OrderChildEnum.ExitNoticeStatus.NOTIFIED.getCode());
        //看日志为已发短信
    }

    /**
     * 状态为已装货，超出范围，发短信，修改状态，修改已发短信状态
     */
    @Test
    void testOrderChildMessageNoticeListConfigEnabled2() {
        //模拟两个运单
        List<OrderChild> mockOrderChildList = new ArrayList<>();
        OrderChild child1 = new OrderChild();
        child1.setChildNo("childNo1");
        child1.setOrderGoodsNo("orderGoods1");
        child1.setTruckNo("truckNo1");
        child1.setRemoveLoadLimitStatus(0);
        child1.setExitNoticeStatus(0);
        //到达货源地
        child1.setStatus(OrderChildEnum.Status.LOAD.getCode());
        child1.setDriverMobile("12345678901");
        mockOrderChildList.add(child1);
        when(orderChildDao.listOrderChild(anyList(), any(), any())).thenReturn(mockOrderChildList);

        Map<String, TruckTraceDTO> truckTraceMap = new HashMap<>();
        TruckTraceDTO truckTraceDTO = new TruckTraceDTO();
        truckTraceDTO.setLocation(new BigDecimal[]{BigDecimal.ONE, BigDecimal.TEN});
        truckTraceDTO.setTruckNo("truckNo1");
        truckTraceMap.put("truckNo1", truckTraceDTO);

        when(redisTemplate.opsForHash()).thenReturn(hashOps);
        when(hashOps.entries(RedisConstants.ZJXL_TRUCK_TRACE_LIST)).thenReturn(truckTraceMap);

        OrderGoods orderGoods = new OrderGoods();

        //货单
        when(orderGoodsDao.getByOrderGoodsNo(child1.getOrderGoodsNo())).thenReturn(Optional.of(orderGoods));
        when(driverNoticeConfigService.listConfig()).thenReturn(mockDriverNoticeConfigVO());


        // gdRoute
        GdRouteDTO gdRoute = new GdRouteDTO();
        //设置3000 ，超出提醒范围了
        gdRoute.setDistance(3000);
        // 假设高德服务返回了一个有效的路线
        Mockito.when(gdService.getRoute(any(), any(), any(), any())).thenReturn(Collections.singletonList(gdRoute));


        App app = new App();
        app.setAppNo("appNo");
        app.setAppKey("appKey");
        app.setCallback("callback");
        Mockito.when(appConfig.getPurchaseManageApp()).thenReturn(app);
        // 调用方法
        orderChildService.orderChildMessageNotice();

        SupervisionLoadInfoDto supervisionLoadInfoDto = new SupervisionLoadInfoDto();
        supervisionLoadInfoDto.setTaskAddress("aaaa");
        supervisionLoadInfoDto.setTaskContracts("bbbb");
        supervisionLoadInfoDto.setTaskMobile("18888888888");
        Result<SupervisionLoadInfoDto> r = Result.ok(supervisionLoadInfoDto);

        // todo: jiangwujie  此处因为无法模拟静态方法，所以这个测试方法是不通过的， 有机会再说
        Mockito.<Result<SupervisionLoadInfoDto>>when(OpenClient.doAction(any(), any())).thenReturn(r);

        //验证运单状态
        assertEquals(child1.getEnterExitSendStatus(), OrderChildEnum.EnterExitSendStatus.DRIVE_OUT.getCode());
        assertEquals(child1.getExitNoticeStatus(), OrderChildEnum.ExitNoticeStatus.NOTIFIED.getCode());
    }

    /**
     * 验证取消监装限制
     *
     * @return
     */
    @Test
    public void test_orderChildMessageNotice_removeLimit() throws Exception {
        //模拟两个运单
        List<OrderChild> mockOrderChildList = new ArrayList<>();
        OrderChild child1 = new OrderChild();
        child1.setChildNo("childNo1");
        child1.setOrderGoodsNo("orderGoods1");
        child1.setTruckNo("truckNo1");
        child1.setRemoveLoadLimitStatus(0);
        child1.setExitNoticeStatus(0);
        child1.setEnterExitSendStatus(OrderChildEnum.EnterExitSendStatus.INIT.getCode());
        child1.setRemoveLoadLimitStatus(OrderChildEnum.RemoveLoadLimitStatus.REMOVED.getCode());
        //到达货源地
        child1.setStatus(OrderChildEnum.Status.ARRIVE_SEND.getCode());
        child1.setDriverMobile("12345678901");
        mockOrderChildList.add(child1);
        when(orderChildDao.listOrderChild(anyList(), any(), any())).thenReturn(mockOrderChildList);

        Map<String, TruckTraceDTO> truckTraceMap = new HashMap<>();
        TruckTraceDTO truckTraceDTO = new TruckTraceDTO();
        truckTraceDTO.setLocation(new BigDecimal[]{BigDecimal.ONE, BigDecimal.TEN});
        truckTraceDTO.setTruckNo("truckNo1");
        truckTraceMap.put("truckNo1", truckTraceDTO);

        when(redisTemplate.opsForHash()).thenReturn(hashOps);
        when(hashOps.entries(RedisConstants.ZJXL_TRUCK_TRACE_LIST)).thenReturn(truckTraceMap);

        OrderGoods orderGoods = new OrderGoods();

        //货单
        when(orderGoodsDao.getByOrderGoodsNo(child1.getOrderGoodsNo())).thenReturn(Optional.of(orderGoods));
        when(driverNoticeConfigService.listConfig()).thenReturn(mockDriverNoticeConfigVO());


        // 调用方法
        orderChildService.orderChildMessageNotice();

        //验证运单状态
        assertEquals(child1.getEnterExitSendStatus(), OrderChildEnum.EnterExitSendStatus.INIT.getCode());
        assertEquals(child1.getExitNoticeStatus(), OrderChildEnum.ExitNoticeStatus.NOT_NOTIFIED.getCode());
        //看日志为已发短信
    }


    /**
     * 状态为到达货源地，未超出范围，修改驶入驶出状态，修改通知状态
     */
    @Test
    void testOrderChildMessageNotice_inRange() {
        //模拟两个运单
        List<OrderChild> mockOrderChildList = new ArrayList<>();
        OrderChild child1 = new OrderChild();
        child1.setChildNo("childNo1");
        child1.setOrderGoodsNo("orderGoods1");
        child1.setTruckNo("truckNo1");
        //驶离
        child1.setEnterExitSendStatus(OrderChildEnum.EnterExitSendStatus.DRIVE_OUT.getCode());
        child1.setRemoveLoadLimitStatus(0);
        child1.setExitNoticeStatus(1);
        //到达货源地
        child1.setStatus(OrderChildEnum.Status.ARRIVE_SEND.getCode());
        child1.setDriverMobile("12345678901");
        mockOrderChildList.add(child1);
        when(orderChildDao.listOrderChild(anyList(), any(), any())).thenReturn(mockOrderChildList);

        Map<String, TruckTraceDTO> truckTraceMap = new HashMap<>();
        TruckTraceDTO truckTraceDTO = new TruckTraceDTO();
        truckTraceDTO.setLocation(new BigDecimal[]{BigDecimal.ONE, BigDecimal.TEN});
        truckTraceDTO.setTruckNo("truckNo1");
        truckTraceMap.put("truckNo1", truckTraceDTO);

        when(redisTemplate.opsForHash()).thenReturn(hashOps);
        when(hashOps.entries(RedisConstants.ZJXL_TRUCK_TRACE_LIST)).thenReturn(truckTraceMap);

        OrderGoods orderGoods = new OrderGoods();

        //货单
        when(orderGoodsDao.getByOrderGoodsNo(child1.getOrderGoodsNo())).thenReturn(Optional.of(orderGoods));
        when(driverNoticeConfigService.listConfig()).thenReturn(mockDriverNoticeConfigVO());


        // gdRoute
        GdRouteDTO gdRoute = new GdRouteDTO();
        // 未超出范围
        gdRoute.setDistance(1000);
        // 假设高德服务返回了一个有效的路线
        Mockito.when(gdService.getRoute(any(), any(), any(), any())).thenReturn(Collections.singletonList(gdRoute));


        // 调用方法
        orderChildService.orderChildMessageNotice();

        //验证运单状态 -> 驶入
        assertEquals(child1.getEnterExitSendStatus(), OrderChildEnum.EnterExitSendStatus.DRIVE_IN.getCode());
        // 通知状态改为未通知
        assertEquals(child1.getExitNoticeStatus(), OrderChildEnum.ExitNoticeStatus.NOT_NOTIFIED.getCode());
    }


    private DriverNoticeConfigVO mockDriverNoticeConfigVO() {
        DriverNoticeConfigVO configVO = new DriverNoticeConfigVO();
        //启用
        configVO.setStatus(1);
        //距离2公里
        configVO.setNoticeTriggerDistance(new BigDecimal(2));
        return configVO;
    }

}
