package com.ruoyi.app.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.service.UserService;
import com.ruoyi.app.utils.PayPush;
import com.ruoyi.app.utils.event.PushEventService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.PosStore;
import com.ruoyi.system.domain.UserBilling;
import com.ruoyi.system.service.IInfoUserService;
import com.ruoyi.system.service.IPosOrderService;
import com.ruoyi.system.service.IPosStoreService;
import com.ruoyi.system.service.IUserBillingService;
import com.ruoyi.system.utils.Auth;
import com.ruoyi.system.utils.JwtUtil;
import com.ruoyi.system.utils.OrderLogHelper;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.ruoyi.app.order.dto.PickupOrderInput;

@RestController
@RequestMapping("/system/orderQsOprate")
public class PosOrderQsOprateController extends BaseController {
    @Autowired
    private IPosOrderService posOrderService;
    @Autowired
    private IInfoUserService infoUserService;
    @Autowired
    private PushEventService pushEventService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private UserService userService;
    @Autowired
    private IUserBillingService userBillingService;
    @Autowired
    private IPosStoreService posStoreService;
    @Autowired
    private OrderLogHelper orderLogHelper;
    @Autowired
    private OrderLifecycleService orderLifecycleService;
    @Autowired
    private MerchantNotificationRouter merchantNotificationRouter;

    /**
     * 骑手接单：校验 type=0 且 afterSaleStatus=0，设置 deliveryStatus=1
     */
    @Anonymous
    @Auth
    @GetMapping("/acceptOrder")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult acceptOrder(@RequestHeader String token, @RequestParam Long id) {
        JwtUtil jwtUtil = new JwtUtil();
        PayPush push = new PayPush();
        String qsId = jwtUtil.getusid(token);
        InfoUser qsRider = requireRider(qsId);
        if (!qsRider.supportsDeliveryType("FOOD")) {
            throw new ServiceException(MessageUtils.message("no.user.delivery.type.not.enabled"));
        }
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.found"));
        }
        if (order.getType() != null && order.getType() != 0L) {
            throw new ServiceException("仅外送订单支持骑手接单");
        }
        if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) {
            throw new ServiceException("订单存在售后申请，无法操作");
        }
        // 线下转账单(payType=6)：商家确认收款前骑手不可接单（抢单列表已过滤 payStatus=1，此处防绕过接口直调）
        if (OrderLifecycleService.PAY_TYPE_TRANSFER.equals(order.getPayType())
                && !Long.valueOf(1L).equals(order.getPayStatus())) {
            throw new ServiceException(MessageUtils.message("no.order.transfer.not.paid"));
        }
        PosOrder posOrder = new PosOrder();
        posOrder.setId(order.getId());
        posOrder.setDeliveryStatus(1L);
        posOrder.setQsId(Long.valueOf(qsId));

        InfoUser qsUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(qsId)));
        String qsName = qsUser != null ? qsUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 3, Long.valueOf(qsId), qsName, "骑手" + qsName + "接单成功");

        return setOrderQsState(posOrder, qsId, push, qsName);
    }

    /**
     * 骑手取餐：校验 type=0 且 afterSaleStatus=0，设置 deliveryStatus=2
     */
    @Anonymous
    @Auth
    @PostMapping("/pickupOrder")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult pickupOrder(@RequestHeader String token, @RequestBody PickupOrderInput input) {
        JwtUtil jwtUtil = new JwtUtil();
        PayPush push = new PayPush();
        String qsId = jwtUtil.getusid(token);
        requireRider(qsId);
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, input.getId()));
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.found"));
        }
        if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) {
            throw new ServiceException("订单存在售后申请，无法操作");
        }
        PosOrder posOrder = new PosOrder();
        posOrder.setId(order.getId());
        posOrder.setDeliveryStatus(2L);
        posOrder.setQsImg(input.getQsImg());

        InfoUser qsUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(qsId)));
        String qsName = qsUser != null ? qsUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 3, Long.valueOf(qsId), qsName, "骑手" + qsName + "已取餐");

        return setOrderQsState(posOrder, qsId, push, qsName);
    }

    /**
     * 骑手送达：设置 deliveryStatus=3
     */
    @Anonymous
    @Auth
    @PostMapping("/deliverOrder")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deliverOrder(@RequestHeader String token, @RequestBody PickupOrderInput input) {
        JwtUtil jwtUtil = new JwtUtil();
        PayPush push = new PayPush();
        String qsId = jwtUtil.getusid(token);
        requireRider(qsId);
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, input.getId()));
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.found"));
        }
        PosOrder posOrder = new PosOrder();
        posOrder.setId(order.getId());
        posOrder.setQsImg(input.getQsImg());
        posOrder.setDeliveryStatus(3L);
        posOrder.setSdTime(new Date());

        InfoUser qsUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(qsId)));
        String qsName = qsUser != null ? qsUser.getNickName() : "";
        return setOrderQsState(posOrder, qsId, push, qsName);
    }

    //骑手接单、取餐、送达
    private AjaxResult setOrderQsState(PosOrder posOrder, String qsId, PayPush push, String qsName) {
        String lockKey = "order:qs:lock:" + posOrder.getId();
        RLock lock = redissonClient.getLock(lockKey);
        try {
            var local = LocaleContextHolder.getLocale();
            logger.info("骑手接单local信息：" + local.getLanguage());
            logger.info(JSON.toJSONString(local));
            // 尝试获取锁
            if (lock.tryLock(20L, 10L, TimeUnit.SECONDS)) {
                boolean releaseInfinally = true;
                try {
                    requireRider(qsId);
                    PosOrder orst = posOrderService.getById(posOrder.getId());
                    if (orst.getDeliveryStatus() != null && orst.getDeliveryStatus() == 1L && posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
                        throw new ServiceException(MessageUtils.message("no.order.snatched"));
                    }
                    if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
                        QueryWrapper<PosOrder> wrapper = new QueryWrapper<>();
                        wrapper.eq("qs_id", qsId);
                        wrapper.in("delivery_status", 1, 2);
                        wrapper.in("state", 0, 1, 2);
                        wrapper.eq("after_sale_status", 0);
                        List<PosOrder> orsts = posOrderService.list(wrapper);
                        if (orsts.size() > 0) {
                            throw new ServiceException(MessageUtils.message("no.exist.undelivered.order"));
                        }
                    }
                    boolean delivered = posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L;
                    boolean org;
                    if (delivered) {
                        orderLifecycleService.completeDeliveryByRider(posOrder.getId(), Long.valueOf(qsId),
                                qsName, posOrder.getQsImg());
                        posOrder.setState(3L);
                        org = true;
                    } else if (Long.valueOf(1L).equals(posOrder.getDeliveryStatus())) {
                        orderLifecycleService.acceptDeliveryByRider(posOrder.getId(), Long.valueOf(qsId));
                        org = true;
                    } else {
                        orderLifecycleService.pickupDeliveryByRider(posOrder.getId(), Long.valueOf(qsId),
                                posOrder.getQsImg());
                        org = true;
                    }
                    if (org) {
                        //到付订单,骑手送达时设置用户账单为完成
                        if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L && "1".equals(orst.getCollectPayment())) {
                            updateUserBill(orst.getDdId(), orst.getUserId(), orst.getQsId());
                        }
                        InfoUser user = infoUserService.getById(orst.getUserId());
                        releaseInfinally = false;
                        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                            @Override
                            public void afterCommit() {
                                if (lock.isHeldByCurrentThread()) {
                                    lock.unlock();
                                }
                                // 给用户推送（骑手已接单/配送中/已送达）
                                if (user != null && !StringUtils.isEmpty(user.getCid())) {
                                    String userTitle = "no.message.push.message";
                                    String userContent = "no.message.push.delivery.personnel.receiving.order";
                                    if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 2L) {
                                        userContent = "no.message.push.delivery.personnel.qspsz.order";
                                    } else if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L) {
                                        userContent = "no.message.push.delivery.personnel.qsysd.order";
                                    }
                                    final String finalUserContent = userContent;
                                    String userBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(orst.getState()));
                                    Long userUserId = user.getUserId();
                                    String userCid = user.getCid();
                                    String userCidType = "";
                                    String userDdId = String.valueOf(orst.getDdId());
                                    AsyncManager.me().execute(new TimerTask() {
                                        @Override
                                        public void run() {
                                            PayPush.userPushHandleLocal(push, pushEventService, userUserId, userCid, userTitle, finalUserContent, userBody, userCidType, userDdId);
                                        }
                                    });
                                }
                                // 给商家推送（骑手已接单时）
                                if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
                                    String shTitle = "no.message.push.message";
                                    String shContent = "no.message.push.rider.accepted.merchant";
                                    String shBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(orst.getState()));
                                    String shDdId = String.valueOf(orst.getDdId());
                                    AsyncManager.me().execute(new TimerTask() {
                                        @Override
                                        public void run() {
                                            merchantNotificationRouter.sendStoreNotification(orst.getMdId(), orst.getShId(),
                                                    shTitle, shContent, shBody, shDdId);
                                        }
                                    });
                                }
                            }
                        });
                        return success(MessageUtils.message("no.modify.success"), posOrder.getId());
                    } else {
                        return error();
                    }
                } finally {
                    if (releaseInfinally && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
        }
    }

    private InfoUser requireRider(String userId) {
        if (userId == null) {
            throw new ServiceException(MessageUtils.message("no.wallet.noexist.userinfo"));
        }
        InfoUser user = userService.checkUserStatus(Long.valueOf(userId));
        if (!"2".equals(user.getUserType())) {
            throw new ServiceException(MessageUtils.message("rider.operation.role.required"));
        }
        return user;
    }

    /**
     * 更新用户用户账单
     *
     * @param ddId
     * @param userId
     * @param qsId
     */
    private void updateUserBill(String ddId, Long userId, Long qsId) {
        QueryWrapper<UserBilling> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("dd_id", ddId);
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("type", "3");
        UserBilling userBill = userBillingService.getOne(queryWrapper);
        if (userBill != null) {
            userBill.setState("0");
            userBill.setIllustrate("Rider Payment Order");
            userBill.setBalancePay("1");
            userBill.setPaymentId(String.valueOf(qsId));
            userBillingService.saveOrUpdate(userBill);
        }
    }

    /**
     * newTask 距离上限（公里），从字典 sys_qs_newtask_distance 取；未配置/非法返回 null（不过滤）。
     */
    private Integer getNewTaskDistanceLimit() {
        try {
            List<SysDictData> list = DictUtils.getDictCache("sys_qs_newtask_distance");
            if (list != null && !list.isEmpty()) {
                return Integer.parseInt(list.get(0).getDictValue());
            }
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 骑手端订单列表（Tab分页）
     */
    @Anonymous
    @Auth
    @GetMapping("/orderList")
    public AjaxResult orderList(@RequestHeader String token, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String tab, @RequestParam(required = false) BigDecimal longitude, @RequestParam(required = false) BigDecimal latitude) {
        JwtUtil jwtUtil = new JwtUtil();
        String qsId = jwtUtil.getusid(token);
        Long riderId = Long.valueOf(qsId);

        // 派单按骑手审核资料选择的配送类型过滤；空类型的历史骑手视为兼容全部
        if ("newTask".equals(tab)) {
            InfoUser rider = requireRider(qsId);
            if (!rider.supportsDeliveryType("FOOD")) {
                throw new ServiceException(MessageUtils.message("no.user.delivery.type.not.enabled"));
            }
        }

        LambdaQueryWrapper<PosOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PosOrder::getIsDisplay,true);
        switch (tab) {
            case "newTask":
                wrapper.eq(PosOrder::getType, 0L).eq(PosOrder::getDeliveryStatus, 0L)
                        .eq(PosOrder::getState, 0L).eq(PosOrder::getPayStatus, 1L)
                        .eq(PosOrder::getAfterSaleStatus, 0L).isNull(PosOrder::getQsId);
                if (longitude != null && latitude != null) {
                    // 距离上限（公里）从字典取，未配置则不过滤
                    Integer limitKm = getNewTaskDistanceLimit();
                    if (limitKm != null) {
                        long limitMeters = limitKm.longValue() * 1000L;
                        wrapper.apply("ST_Distance_Sphere(point(longitude, latitude), point({0}, {1})) <= {2}",
                                longitude, latitude, limitMeters);
                    }
                    wrapper.last("ORDER BY ST_Distance_Sphere(point(longitude, latitude), point(" + longitude + ", " + latitude + ")) ASC");
                } else {
                    wrapper.orderByDesc(PosOrder::getCretim);
                }
                break;
            case "toPickup":
                wrapper.eq(PosOrder::getDeliveryStatus, 1L).eq(PosOrder::getQsId, riderId)
                        .in(PosOrder::getState, 0L, 1L, 2L)
                        .eq(PosOrder::getAfterSaleStatus, 0L).orderByAsc(PosOrder::getCretim);
                break;
            case "delivering":
                wrapper.eq(PosOrder::getDeliveryStatus, 2L).eq(PosOrder::getQsId, riderId)
                        .eq(PosOrder::getState, 2L).eq(PosOrder::getAfterSaleStatus, 0L)
                        .orderByAsc(PosOrder::getCretim);
                break;
                //已送达
            case "completed":
                wrapper.eq(PosOrder::getDeliveryStatus, 3L).eq(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim);
                break;
            case "cancelled":
                wrapper.eq(PosOrder::getState, 4L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByDesc(PosOrder::getCretim);
                break;
            case "refund":
                wrapper.gt(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim);
                break;
            default:
                break;
        }

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, size);
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> result = posOrderService.page(pageParam, wrapper);
        Set<Long> mdIds = result.getRecords().stream().map(PosOrder::getMdId).filter(Objects::nonNull).collect(Collectors.toSet());
        Set<Long> userIds=result.getRecords().stream().map(PosOrder::getUserId).filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, PosStore> storeMap = mdIds.isEmpty() ? Collections.emptyMap() :
                posStoreService.listByIds(mdIds).stream().collect(Collectors.toMap(PosStore::getId, s -> s));
        Map<Long, InfoUser> userMap = userIds.isEmpty() ? Collections.emptyMap() :
                infoUserService.listByIds(userIds).stream().collect(Collectors.toMap(InfoUser::getUserId, s -> s));
        JSONArray arr=new JSONArray();
        for (PosOrder order : result.getRecords()) {
            // 自动序列化所有PosOrder字段，新增字段无需手动添加
            JSONObject org = JSON.parseObject(
                    JSON.toJSONStringWithDateFormat(order, "yyyy-MM-dd HH:mm:ss")
            );
            org.put("juli",null);
            // 计算距离(km)
            if (order.getLongitude() != null && order.getLatitude() != null && longitude != null && latitude != null) {
                double lat1 = Math.toRadians(order.getLatitude().doubleValue());
                double lat2 = Math.toRadians(latitude.doubleValue());
                double dlat = lat2 - lat1;
                double dlng = Math.toRadians(longitude.doubleValue() - order.getLongitude().doubleValue());
                double a = Math.sin(dlat / 2) * Math.sin(dlat / 2)
                        + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlng / 2) * Math.sin(dlng / 2);
                double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
//                order.setJuli(Math.round(6371 * c * 100.0) / 100.0);
                org.put("juli",Math.round(6371 * c * 100.0) / 100.0);
            }


            // 以下为非PosOrder字段或需要特殊处理的字段
            org.put("store", storeMap.get(order.getMdId().intValue()));
            org.put("user",userMap.get(order.getUserId()));
            arr.add(org);
        }
        JSONObject org=new JSONObject();
        org.put("records",arr);
        org.put("total",result.getTotal());
        org.put("current",result.getCurrent());
        return success(org);
    }

    /**
     * 返回订单详情，带上store、user信息（返回格式与 orderList 列表项一致，仅返回单条）
     * @param token
     * @param ddId
     * @return
     */
    @Anonymous
    @Auth
    @GetMapping("/getOrderDetial")
    public AjaxResult getOrderDetial(@RequestHeader String token, @RequestParam String ddId) {
        JwtUtil jwtUtil = new JwtUtil();
        String qsId = jwtUtil.getusid(token);
        Long riderId = Long.valueOf(qsId);

        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getDdId, ddId).eq(PosOrder::getQsId,riderId));
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.found"));
        }
        // 序列化格式与 orderList 列表项保持一致：PosOrder 全字段 + juli + store + user
        JSONObject org = JSON.parseObject(
                JSON.toJSONStringWithDateFormat(order, "yyyy-MM-dd HH:mm:ss")
        );
        org.put("juli", null);
        org.put("store", order.getMdId() == null ? null : posStoreService.getById(order.getMdId().intValue()));
        org.put("user", order.getUserId() == null ? null : infoUserService.getById(order.getUserId()));
        return success(org);
    }

}
