package com.kym.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.common.utils.OrderUtils;
import com.kym.entity.Account;
import com.kym.entity.ParkingCouponRecord;
import com.kym.entity.User;
import com.kym.entity.WashOrder;
import com.kym.entity.WashStation;
import com.kym.entity.awoara.OrderInfo;
import com.kym.entity.common.PageBean;
import com.kym.entity.common.PageParams;
import com.kym.entity.queryParams.DeviceQueryParams;
import com.kym.entity.queryParams.StatQueryParam;
import com.kym.entity.queryParams.WashOrderQueryParams;
import com.kym.entity.vo.StationTrendVo;
import com.kym.entity.vo.WashOrderVo;
import com.kym.mapper.WashOrderMapper;
import com.kym.service.AccountService;
import com.kym.service.OrderSettlementService;
import com.kym.service.ParkingCouponRecordService;
import com.kym.service.UserService;
import com.kym.service.WashOrderService;
import com.kym.service.WashStationService;
import com.kym.service.awoara.AwoaraService;
import com.kym.service.cache.KymCache;
import com.kym.service.mybatisplus.MyBaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 洗车订单表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2024-09-11
 */
@Slf4j
@Service
public class WashOrderServiceImpl extends MyBaseServiceImpl<WashOrderMapper, WashOrder> implements WashOrderService {

    private final AwoaraService awoaraService;
    private final AccountService accountService;
    private final WashStationService washStationService;
    private final UserService userService;
    private final OrderSettlementService orderSettlementService;
    private final ParkingCouponRecordService parkingCouponRecordService;

    @Value("${kym.domain}")
    private String DOMAIN;

    public WashOrderServiceImpl(AwoaraService awoaraService, AccountService accountService,
                                @Lazy WashStationService washStationService, UserService userService,
                                @Lazy OrderSettlementService orderSettlementService,
                                ParkingCouponRecordService parkingCouponRecordService) {
        this.awoaraService = awoaraService;
        this.accountService = accountService;
        this.washStationService = washStationService;
        this.userService = userService;
        this.orderSettlementService = orderSettlementService;
        this.parkingCouponRecordService = parkingCouponRecordService;
    }

    /**
     * 创建订单（启动洗车机）
     *
     * @param params
     * @return
     */
    @Override
    public String createOrder(DeviceQueryParams params) {
        // 校验余额
        var account = accountService.getAccountByUserId(StpUtil.getLoginIdAsLong());
        if (account.getBalance() < Account.MIN_BALANCE) {
            throw new BusinessException("余额不足，请保持余额不低于2元！");
        }

        // 校验用户是否有未完结的订单
        var unfinishedOrder = lambdaQuery()
                .eq(WashOrder::getUserId, StpUtil.getLoginIdAsLong())
                .and(wrapper -> wrapper
                        .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                        .or()
                        .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付))
                .list();
        if (!unfinishedOrder.isEmpty()) {
            throw new BusinessException("您有未完结的订单！");
        }

        // 检查设备是否有僵死订单（设备显示忙碌但订单实际已超时）
        checkAndResolveStaleOrder(params.getProductKey(), params.getDeviceName());

        var memberName = StpUtil.getSession().getString(User.ST_SESSION_KEY_MOBILE);
        var orderId = OrderUtils.getOrderNo();

        // 请求阿里云lot
        var createOrder = awoaraService.createOrder(params.getProductKey(), params.getDeviceName(),
                orderId,
                memberName,
                account.getBalance(),
                Account.NO_DISCOUNT,
                // 本次开机最大消费金额
                account.getBalance());
        // 首次消费：无归属站点的用户自动归属到当前设备所在站点
        long userId = StpUtil.getLoginIdAsLong();
        var user = userService.getById(userId);
        var userStationId = user != null ? user.getStationId() : null;
        if (CommUtil.isEmptyOrNull(userStationId)) {
            userService.lambdaUpdate()
                    .set(User::getStationId, params.getStationId())
                    .eq(User::getId, userId)
                    .update();
            StpUtil.getSession().set("stationId", params.getStationId());
            KymCache.INSTANCE.putUserId2StationId(Map.of(userId, params.getStationId()));
            userStationId = params.getStationId();
        }

        var washOrder = new WashOrder()
                .setUserId(StpUtil.getLoginIdAsLong())
                .setStationId(params.getStationId())
                .setProductKey(params.getProductKey())
                .setDeviceName(params.getDeviceName())
                .setShortId(KymCache.INSTANCE.getShortIdByProductKeyAndDeviceName(params.getProductKey(), params.getDeviceName()))
                .setOpenType(WashOrder.START_CLOSE_TYPE_网络)
                .setOrderId(orderId)
                .setOrderIdLocal(createOrder.getOrder_id_local())
                .setMemberDiscount(Account.NO_DISCOUNT)
                .setPrepayMoney(account.getBalance())
                .setStartTime(LocalDateTime.now())
                .setOrderStatus(WashOrder.ORDER_STATUS_开机)
                .setPayStatus(WashOrder.PAY_STATUS_未支付)
                .setIsCross(!params.getStationId().equals(userStationId));
        save(washOrder);
        return orderId;
    }

    @Override
    public void closeOrder(DeviceQueryParams params) {
        var order = lambdaQuery()
                .eq(WashOrder::getProductKey, params.getProductKey())
                .eq(WashOrder::getDeviceName, params.getDeviceName())
                .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .one();
        if (order == null) {
            return;
        }
        if (order.getUserId() != StpUtil.getLoginIdAsLong()) {
            throw new BusinessException("您没有权限关闭该订单!");
        }

        // 尝试发送关闭命令，失败后重试1次
        boolean sent = sendCloseOrderWithRetry(params.getProductKey(), params.getDeviceName(), order.getOrderId(), 1);
        if (sent) {
            return;
        }

        // RRpc 失败，主动查询设备订单状态
        log.warn("订单 {} 关闭命令发送失败，尝试主动查询设备状态", order.getOrderId());
        try {
            OrderInfo orderInfo = awoaraService.queryOrder(params.getProductKey(), params.getDeviceName(), order.getOrderId());
            if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
                log.info("订单 {} 设备已关闭，执行结算", order.getOrderId());
                orderSettlementService.settleOrder(order, orderInfo);
                return;
            }
            if (orderInfo != null && (orderInfo.getClose_type() == null || orderInfo.getClose_type().isEmpty())) {
                // 设备还在运行，尝试强制关闭
                log.info("订单 {} 设备仍在运行，尝试强制关闭", order.getOrderId());
                try {
                    awoaraService.forceCloseOrder(params.getProductKey(), params.getDeviceName());
                } catch (Exception fe) {
                    log.error("订单 {} 强制关闭也失败", order.getOrderId(), fe);
                }
            }
        } catch (Exception e) {
            log.error("订单 {} 主动查询设备状态也失败", order.getOrderId(), e);
        }

        throw new BusinessException("关闭订单失败，请稍后重试或联系管理员");
    }

    @Override
    public void forceSettleOrder(String orderId) {
        var order = lambdaQuery()
                .eq(WashOrder::getOrderId, orderId)
                .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .one();
        if (order == null) {
            throw new BusinessException("未找到该订单或订单已完结");
        }

        // 尝试通过 RRpc 发送关闭命令
        sendCloseOrderWithRetry(order.getProductKey(), order.getDeviceName(), order.getOrderId(), 1);

        // 查询设备订单状态进行结算
        log.info("订单 {} 已发送关闭命令，查询设备订单状态进行结算", order.getOrderId());
        try {
            OrderInfo orderInfo = awoaraService.queryOrder(order.getProductKey(), order.getDeviceName(), order.getOrderId());
            if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
                log.info("订单 {} 设备已关闭，执行结算", order.getOrderId());
                orderSettlementService.settleOrder(order, orderInfo);
                return;
            }
            if (orderInfo != null && (orderInfo.getClose_type() == null || orderInfo.getClose_type().isEmpty())) {
                // 设备还在运行，尝试强制关闭
                log.info("订单 {} 设备仍在运行，尝试强制关闭", order.getOrderId());
                try {
                    awoaraService.forceCloseOrder(order.getProductKey(), order.getDeviceName());
                } catch (Exception fe) {
                    log.error("订单 {} 强制关闭也失败", order.getOrderId(), fe);
                }
            }
        } catch (Exception e) {
            log.error("订单 {} 主动查询设备状态也失败", order.getOrderId(), e);
        }

        throw new BusinessException("强制结算失败，请稍后重试或联系管理员");
    }

    private boolean sendCloseOrderWithRetry(String productKey, String deviceName, String orderId, int maxRetries) {
        for (int i = 0; i <= maxRetries; i++) {
            try {
                awoaraService.closeOrder(productKey, deviceName, orderId);
                return true;
            } catch (Exception e) {
                if (i < maxRetries) {
                    log.warn("订单 {} 关闭命令第{}次失败，准备重试", orderId, i + 1, e);
                } else {
                    log.error("订单 {} 关闭命令{}次均失败", orderId, maxRetries + 1, e);
                }
            }
        }
        return false;
    }

    /**
     * 检查设备是否有僵死订单，有则尝试清理
     */
    private void checkAndResolveStaleOrder(String productKey, String deviceName) {
        var staleOrder = lambdaQuery()
                .eq(WashOrder::getProductKey, productKey)
                .eq(WashOrder::getDeviceName, deviceName)
                .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .one();
        if (staleOrder == null) {
            return;
        }
        log.warn("设备 {}/{} 存在未完结订单 {}，尝试查询设备实际状态", productKey, deviceName, staleOrder.getOrderId());
        try {
            OrderInfo orderInfo = awoaraService.queryOrder(productKey, deviceName, staleOrder.getOrderId());
            if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
                log.info("设备实际已关闭订单 {}，执行结算", staleOrder.getOrderId());
                orderSettlementService.settleOrder(staleOrder, orderInfo);
            }
        } catch (Exception e) {
            log.warn("查询设备订单状态失败，跳过清理：{}", e.getMessage());
        }
    }

    /**
     * 查询订单详情
     *
     * @param params
     * @return
     */
    @Override
    public WashOrder queryOrder(WashOrderQueryParams params) {
        // 非实时数据
        WashOrder order = lambdaQuery()
                .eq(WashOrder::getOrderId, params.getOrderId())
                .one();
        if (null != params.getUserId()) {
            CommUtil.asserts(null != order && order.getUserId().equals(StpUtil.getLoginIdAsLong()),
                    "订单不存在或您没有权限查看该订单!");
        }
        return order;
    }

    /**
     * 查询停车减免订单
     *
     * @param unionid
     * @return
     */
    @Override
    public String getParkingDiscounts(String unionid) {
        var user = userService.lambdaQuery().eq(User::getUnionid, unionid).one();
        CommUtil.asserts(null != user, "用户信息异常：无此用户");
        // 查询用户24小时内的订单
        var orders = lambdaQuery()
                .eq(WashOrder::getUserId, user.getId())
                .ge(WashOrder::getStartTime, LocalDateTime.now().minusHours(24))
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
                .orderByDesc(WashOrder::getId)
                .list();

        CommUtil.asserts(CommUtil.isEmptyOrNull(orders) && (orders.stream().mapToInt(WashOrder::getAmount).sum() >= 0),
                "抱歉：无停车场洗车记录");

        return washStationService.lambdaQuery().eq(WashStation::getStationId, orders.get(0).getStationId()).one().getParkingQrCode();
    }

    /**
     * 当前用户订单列表
     *
     * @param params
     * @return
     */
    @Override
    public PageBean<WashOrderVo> listMyWashOrder(PageParams params) {
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var res = lambdaQuery()
                .eq(WashOrder::getUserId, StpUtil.getLoginIdAsLong())
                .orderByDesc(WashOrder::getId)
                .list();
        PageInfo<WashOrder> pages = new PageInfo<>(res);
        var voList = pages.getList().stream().map(order -> {
            var vo = new WashOrderVo();
            BeanUtils.copyProperties(order, vo);
            vo.setStationName(KymCache.INSTANCE.getStationNameById(order.getStationId()));
            return vo;
        }).toList();
        PageBean<WashOrderVo> bean = new PageBean<>(voList);
        bean.setPages(pages.getPages());
        bean.setPageNum(pages.getPageNum());
        bean.setPageSize(pages.getPageSize());
        bean.setTotal(pages.getTotal());
        return bean;
    }


    //region 管理后台
    @Override
    public PageBean<WashOrderVo> list(WashOrderQueryParams params) {
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        MPJLambdaWrapper<WashOrder> wrapper = JoinWrappers.lambda(WashOrder.class)
                .selectAsClass(WashOrder.class, WashOrderVo.class)
                .selectAs(User::getMobilePhone, WashOrderVo::getMobilePhone)
                .leftJoin(User.class, User::getId, WashOrder::getUserId)
                .eq(CommUtil.isNotEmptyAndNull(params.getUserId()), WashOrder::getUserId, params.getUserId())
                .eq(CommUtil.isNotEmptyAndNull(params.getMobilePhone()), User::getMobilePhone, params.getMobilePhone())
                .eq(CommUtil.isNotEmptyAndNull(params.getOrderStatus()), WashOrder::getOrderStatus, params.getOrderStatus())
                .eq(CommUtil.isNotEmptyAndNull(params.getPayStatus()), WashOrder::getPayStatus, params.getPayStatus())
                .orderByDesc(WashOrder::getId);
        //连表查询 返回自定义ResultType
        List<WashOrderVo> list = selectJoinList(WashOrderVo.class, wrapper);
        list.forEach(item -> {
            item.setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()));
            item.setUserStationId(KymCache.INSTANCE.getUserStationId(item.getUserId()));
            item.setUserStationName(KymCache.INSTANCE.getStationNameById(item.getUserStationId()));
        });
        return new PageBean<>(list);
    }

    /**
     * 获取订单详情
     * 根据订单号查询，而不是主键ID
     *
     * @param orderId 订单号
     * @return 订单详情
     */
    @Override
    public WashOrderVo detail(String orderId) {
        MPJLambdaWrapper<WashOrder> wrapper = JoinWrappers.lambda(WashOrder.class)
                .selectAsClass(WashOrder.class, WashOrderVo.class)
                .selectAs(User::getMobilePhone, WashOrderVo::getMobilePhone)
                .leftJoin(User.class, User::getId, WashOrder::getUserId)
                .eq(WashOrder::getOrderId, orderId);

        WashOrderVo washOrderVo = selectJoinOne(WashOrderVo.class, wrapper);

        if (washOrderVo != null) {
            washOrderVo.setStationName(KymCache.INSTANCE.getStationNameById(washOrderVo.getStationId()));
            washOrderVo.setUserStationId(KymCache.INSTANCE.getUserStationId(washOrderVo.getUserId()));
            washOrderVo.setUserStationName(KymCache.INSTANCE.getStationNameById(washOrderVo.getUserStationId()));
        }

        return washOrderVo;
    }

    /**
     * 统计指定日期各站点消费金额
     *
     * @param statDay
     * @return
     */
    @Override
    public Map<String, Integer> sumAmountByDate(LocalDate statDay) {
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getAmount, WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
        wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(statDay.plusDays(1), LocalTime.MIN));
        var list = list(wrapper);
        // 按照站点分组统计金额
        return list.stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(WashOrder::getAmount)));
    }

    /**
     * 统计指定日期当月各站点总消费金额
     *
     * @param statDay
     * @return
     */
    @Override
    public Map<String, Integer> sumMonthAmount(LocalDate statDay) {
        var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
        var endTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).plusMonths(1).atTime(LocalTime.MIN);
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getAmount, WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, startTime);
        wrapper.lt(WashOrder::getStartTime, endTime);
        var list = list(wrapper);
        // 按照站点分组统计金额
        return list.stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(WashOrder::getAmount)));
    }

    /**
     * 统计指定日期订单数量
     *
     * @param statDay
     * @return
     */
    @Override
    public Map<String, Integer> countDailyOrders(LocalDate statDay) {
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
        wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(statDay.plusDays(1), LocalTime.MIN));
        // 按照站点分组统计订单数量
        return list(wrapper).stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
    }

    /**
     * 统计指定日期订单数量
     *
     * @param statDay
     * @return
     */
    @Override
    public Map<String, Integer> countMonthOrders(LocalDate statDay) {
        var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
        var endTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).plusMonths(1).atTime(LocalTime.MIN);
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, startTime);
        wrapper.lt(WashOrder::getStartTime, endTime);
        // 按照站点分组统计订单数量
        return list(wrapper).stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
    }

    @Override
    public Map<String, Integer> countDailyActiveUsers(LocalDate statDay) {
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getUserId, WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
        wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(statDay.plusDays(1), LocalTime.MIN));
        wrapper.groupBy(WashOrder::getStationId, WashOrder::getUserId);
        return list(wrapper).stream()
                .collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
    }

    @Override
    public Map<String, Integer> countMonthActiveUsers(LocalDate statDay) {
        var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
        var endTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).plusMonths(1).atTime(LocalTime.MIN);
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getUserId, WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, startTime);
        wrapper.lt(WashOrder::getStartTime, endTime);
        wrapper.groupBy(WashOrder::getStationId, WashOrder::getUserId);
        return list(wrapper).stream()
                .collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
    }

    @Override
    public Map<String, Integer> countDistinctActiveUsers(LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(WashOrder::getUserId, WashOrder::getStationId);
        wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(startDate, LocalTime.MIN));
        wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(endDate.plusDays(1), LocalTime.MIN));
        wrapper.groupBy(WashOrder::getStationId, WashOrder::getUserId);
        return list(wrapper).stream()
                .collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
    }

    @Override
    public WashOrder getOrderInProgressByUserId(long userId) {
        return lambdaQuery()
                .eq(WashOrder::getUserId, userId)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .one();
    }

    @Override
    public List<StationTrendVo> stationTrend(StatQueryParam params) {
        return baseMapper.StationTrend(params);
    }

    @Override
    public String checkParkingCoupon(String mobilePhone) {
        CommUtil.asserts(CommUtil.isNotEmptyAndNull(mobilePhone),"查询手机号不能为空");
        var user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getMobilePhone, mobilePhone));
        if (user == null) {
            throw new BusinessException("请输入注册洗车小程序使用的手机号码！");
        }

        // 优惠券有效期2小时，先查已支付订单
        var orderList = lambdaQuery()
                .eq(WashOrder::getUserId, user.getId())
                .ge(WashOrder::getEndTime, LocalDateTime.now().minusHours(2))
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
                .orderByDesc(WashOrder::getId).list();
        if (!orderList.isEmpty() && orderList.stream().collect(Collectors.summarizingInt(WashOrder::getAmount)).getSum() >= KymCache.INSTANCE.getParkingCouponMinAmountByStationId(orderList.get(0).getStationId())) {
            var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(orderList.get(0).getStationId());
            var code = UUID.randomUUID().toString();
            KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
            parkingCouponRecordService.save(new ParkingCouponRecord()
                    .setCode(code)
                    .setUserId(user.getId())
                    .setStationId(orderList.get(0).getStationId())
                    .setOrderId(orderList.get(0).getOrderId())
                    .setTargetUrl(parkingCouponUrl)
                    .setStatus(ParkingCouponRecord.STATUS_未使用)
                    .setExpireTime(LocalDateTime.now().plusHours(2)));
            return DOMAIN + "/api/parking-coupon?code=" + code;
        }

        // 未找到符合条件的已支付订单，尝试查找僵死订单并主动对账结算
        var staleOrders = lambdaQuery()
                .eq(WashOrder::getUserId, user.getId())
                .ge(WashOrder::getStartTime, LocalDateTime.now().minusHours(2))
                .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
                .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                .orderByDesc(WashOrder::getId).list();

        if (!staleOrders.isEmpty()) {
            boolean reconciled = false;
            for (WashOrder staleOrder : staleOrders) {
                try {
                    OrderInfo orderInfo = awoaraService.queryOrder(staleOrder.getProductKey(), staleOrder.getDeviceName(), staleOrder.getOrderId());
                    if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
                        log.info("停车券查询-订单 {} 设备已关闭，主动结算", staleOrder.getOrderId());
                        orderSettlementService.settleOrder(staleOrder, orderInfo);
                        reconciled = true;
                    }
                } catch (Exception e) {
                    log.warn("停车券查询-订单 {} 查询设备失败：{}", staleOrder.getOrderId(), e.getMessage());
                }
            }

            if (reconciled) {
                // 结算后重新查询已支付订单
                orderList = lambdaQuery()
                        .eq(WashOrder::getUserId, user.getId())
                        .ge(WashOrder::getEndTime, LocalDateTime.now().minusHours(2))
                        .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
                        .orderByDesc(WashOrder::getId).list();
                if (!orderList.isEmpty() && orderList.stream().collect(Collectors.summarizingInt(WashOrder::getAmount)).getSum() >= KymCache.INSTANCE.getParkingCouponMinAmountByStationId(orderList.get(0).getStationId())) {
                    var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(orderList.get(0).getStationId());
                    var code = UUID.randomUUID().toString();
                    KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
                    parkingCouponRecordService.save(new ParkingCouponRecord()
                            .setCode(code)
                            .setUserId(user.getId())
                            .setStationId(orderList.get(0).getStationId())
                            .setOrderId(orderList.get(0).getOrderId())
                            .setTargetUrl(parkingCouponUrl)
                            .setStatus(ParkingCouponRecord.STATUS_未使用)
                            .setExpireTime(LocalDateTime.now().plusHours(2)));
                    return DOMAIN + "/api/parking-coupon?code=" + code;
                }
            }
        }

        throw new BusinessException("不符合优惠条件：订单完成超过2小时或洗车金额不足6元。");
    }
    //endregion
}
