package com.ruoyi.app.order;

import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.utils.event.PushEventService;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.RiderPosition;
import com.ruoyi.system.mapper.RiderPositionMapper;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.service.IInfoUserService;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.List;

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class DeliveryOrderNotificationServiceTest {

    @Test
    void notifiesNearbyAvailableRidersOnlyAfterDeliveryOrderIsPaid() {
        RiderPositionMapper positions = mock(RiderPositionMapper.class);
        DeliveryOrderNotificationService service = spy(new DeliveryOrderNotificationService(
                positions, mock(PushEventService.class)));
        PosOrder order = availableOrder();
        RiderPosition rider = new RiderPosition();
        rider.setRiderId(88L);
        rider.setCid("rider-cid");
        when(positions.getAcceptRiderList(order.getLongitude(), order.getLatitude(), 20))
                .thenReturn(List.of(rider));
        doNothing().when(service).sendAvailableOrderToRider(rider, order);

        service.notifyOrderAvailable(order);

        verify(positions).getAcceptRiderList(order.getLongitude(), order.getLatitude(), 20);
        verify(service).sendAvailableOrderToRider(rider, order);

        order.setPayStatus(0L);
        service.notifyOrderAvailable(order);
        verify(positions).getAcceptRiderList(order.getLongitude(), order.getLatitude(), 20);
        verify(service).sendAvailableOrderToRider(rider, order);
    }

    @Test
    void ignoresOrdersThatAreNotOpenForRiderAssignment() {
        RiderPositionMapper positions = mock(RiderPositionMapper.class);
        DeliveryOrderNotificationService service = new DeliveryOrderNotificationService(
                positions, mock(PushEventService.class));
        PosOrder order = availableOrder();
        order.setState(1L);

        service.notifyOrderAvailable(order);

        verify(positions, never()).getAcceptRiderList(order.getLongitude(), order.getLatitude(), 20);
    }

    @Test
    void userCancellationRoutesMerchantNotificationByActualOrderStore() {
        RiderPositionMapper positions = mock(RiderPositionMapper.class);
        IInfoUserService users = mock(IInfoUserService.class);
        MerchantNotificationRouter router = mock(MerchantNotificationRouter.class);
        DeliveryOrderNotificationService service = new DeliveryOrderNotificationService(
                positions, mock(PushEventService.class), users, router);
        PosOrder order = availableOrder();
        order.setMdId(9L);
        order.setShId(101L);
        order.setUserId(201L);
        order.setQsId(301L);
        InfoUser operator = new InfoUser();
        operator.setUserId(201L);
        operator.setUserType("0");
        when(users.getById(201L)).thenReturn(operator);
        when(users.listByIds(org.mockito.ArgumentMatchers.anyCollection())).thenReturn(List.of());

        service.notifyOrderCancelled(order, 201L);

        verify(router).sendStoreNotification(9L, 101L,
                "no.message.push.message", "no.message.push.order.cancelled",
                OrderPushBodyDto.getJson("DD-DELIVERY", "4", 0), "DD-DELIVERY");
    }

    private static PosOrder availableOrder() {
        PosOrder order = new PosOrder();
        order.setId(10L);
        order.setDdId("DD-DELIVERY");
        order.setType(0L);
        order.setState(0L);
        order.setDeliveryStatus(0L);
        order.setPayStatus(1L);
        order.setAfterSaleStatus(0L);
        order.setLongitude(new BigDecimal("121.5000"));
        order.setLatitude(new BigDecimal("25.0300"));
        return order;
    }
}
