package com.ruoyi.app.order;

import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.utils.PayPush;
import com.ruoyi.app.utils.event.PushEventService;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.RiderPosition;
import com.ruoyi.system.mapper.RiderPositionMapper;
import com.ruoyi.system.service.IInfoUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TimerTask;

/** 外送订单开放接单及取消后的推送。 */
@Service
public class DeliveryOrderNotificationService {
    private static final int RIDER_NOTIFICATION_LIMIT = 20;

    private final RiderPositionMapper riderPositionMapper;
    private final PushEventService pushEventService;
    private final IInfoUserService infoUserService;
    private final MerchantNotificationRouter merchantNotificationRouter;

    public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
                                            PushEventService pushEventService) {
        this(riderPositionMapper, pushEventService, null, null);
    }

    public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
                                            PushEventService pushEventService,
                                            IInfoUserService infoUserService) {
        this(riderPositionMapper, pushEventService, infoUserService, null);
    }

    @Autowired
    public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
                                            PushEventService pushEventService,
                                            IInfoUserService infoUserService,
                                            MerchantNotificationRouter merchantNotificationRouter) {
        this.riderPositionMapper = riderPositionMapper;
        this.pushEventService = pushEventService;
        this.infoUserService = infoUserService;
        this.merchantNotificationRouter = merchantNotificationRouter;
    }

    /** 支付完成且仍待骑手接单时，通知附近可接单骑手。 */
    public void notifyOrderAvailable(PosOrder order) {
        if (!isAvailableForRider(order)) {
            return;
        }
        runAfterCommit(() -> {
            List<RiderPosition> riders = riderPositionMapper.getAcceptRiderList(
                    order.getLongitude(), order.getLatitude(), RIDER_NOTIFICATION_LIMIT);
            if (riders != null) {
                riders.forEach(rider -> sendAvailableOrderToRider(rider, order));
            }
        });
    }

    /** 已分配骑手的外送订单取消后，通知除取消人外的相关方。 */
    public void notifyOrderCancelled(PosOrder order, Long operatorId) {
        if (order == null || !Long.valueOf(0L).equals(order.getType())
                || order.getQsId() == null || infoUserService == null) {
            return;
        }
        runAfterCommit(() -> {
            Set<Long> recipientIds = new LinkedHashSet<>();
            recipientIds.add(order.getUserId());
            recipientIds.add(order.getQsId());
            if (merchantNotificationRouter == null) {
                recipientIds.add(order.getShId());
            }
            recipientIds.remove(null);
            recipientIds.remove(operatorId);
            if (recipientIds.isEmpty()) {
                return;
            }
            List<InfoUser> recipients = infoUserService.listByIds(recipientIds);
            if (recipients != null) {
                recipients.forEach(recipient -> sendCancelledOrder(recipient, order));
            }
            if (merchantNotificationRouter != null && shouldNotifyMerchant(operatorId)) {
                String ddId = String.valueOf(order.getDdId());
                String body = OrderPushBodyDto.getJson(ddId, "4", 0);
                merchantNotificationRouter.sendStoreNotification(order.getMdId(), order.getShId(),
                        "no.message.push.message", "no.message.push.order.cancelled", body, ddId);
            }
        });
    }

    private boolean shouldNotifyMerchant(Long operatorId) {
        if (operatorId == null || infoUserService == null) {
            return true;
        }
        InfoUser operator = infoUserService.getById(operatorId);
        return operator == null || "0".equals(operator.getUserType()) || "2".equals(operator.getUserType());
    }

    void sendAvailableOrderToRider(RiderPosition rider, PosOrder order) {
        if (rider == null || rider.getRiderId() == null) {
            return;
        }
        String ddId = String.valueOf(order.getDdId());
        String body = OrderPushBodyDto.getJson(ddId, String.valueOf(order.getState()), 0);
        AsyncManager.me().execute(new TimerTask() {
            @Override
            public void run() {
                PayPush.qsPushHandleLocal(new PayPush(), pushEventService, rider.getRiderId(), rider.getCid(),
                        "no.message.push.message", "no.message.push.new.order", body, "", ddId);
            }
        });
    }

    void sendCancelledOrder(InfoUser recipient, PosOrder order) {
        if (recipient == null || recipient.getUserId() == null) {
            return;
        }
        String ddId = String.valueOf(order.getDdId());
        String body = OrderPushBodyDto.getJson(ddId, "4", 0);
        AsyncManager.me().execute(new TimerTask() {
            @Override
            public void run() {
                PayPush push = new PayPush();
                if (recipient.getUserId().equals(order.getQsId())) {
                    PayPush.qsPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
                            "no.message.push.message", "no.message.push.order.cancelled", body, "", ddId);
                } else if (recipient.getUserId().equals(order.getShId())) {
                    PayPush.shPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
                            "no.message.push.message", "no.message.push.order.cancelled", body, "", ddId);
                } else {
                    PayPush.userPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
                            "no.message.push.message", "no.message.push.order.cancelled", body, "", ddId);
                }
            }
        });
    }

    private boolean isAvailableForRider(PosOrder order) {
        return order != null
                && Long.valueOf(0L).equals(order.getType())
                && Long.valueOf(0L).equals(order.getState())
                && Long.valueOf(0L).equals(order.getDeliveryStatus())
                && Long.valueOf(1L).equals(order.getPayStatus())
                && Long.valueOf(0L).equals(order.getAfterSaleStatus())
                && order.getQsId() == null;
    }

    private static void runAfterCommit(Runnable action) {
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            action.run();
            return;
        }
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                action.run();
            }
        });
    }
}
