package com.ruoyi.ss.order.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.YPMsgUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.utils.wx.vo.PrepayResponseVO;
import com.ruoyi.ss.balance.domain.UserBalanceQuery;
import com.ruoyi.ss.balance.service.IUserBalanceService;
import com.ruoyi.ss.clean.domain.Clean;
import com.ruoyi.ss.clean.service.ICleanService;
import com.ruoyi.ss.device.domain.DeviceQuery;
import com.ruoyi.ss.device.domain.enums.DeviceStatus;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.dividendDetail.domain.DividendDetail;
import com.ruoyi.ss.dividendDetail.domain.DividendDetailQuery;
import com.ruoyi.ss.dividendDetail.service.IDividendDetailService;
import com.ruoyi.ss.feeRule.domain.FeeRuleVO;
import com.ruoyi.ss.feeRule.service.IFeeRuleService;
import com.ruoyi.ss.intention.domain.IntentionQuery;
import com.ruoyi.ss.intention.service.IIntentionService;
import com.ruoyi.ss.order.domain.Order;
import com.ruoyi.ss.order.domain.OrderBO;
import com.ruoyi.ss.order.domain.OrderQuery;
import com.ruoyi.ss.order.domain.OrderVO;
import com.ruoyi.ss.order.domain.dto.OrderDTO;
import com.ruoyi.ss.order.domain.dto.ProductDTO;
import com.ruoyi.ss.order.domain.dto.ReOrderDTO;
import com.ruoyi.ss.order.domain.enums.OrderType;
import com.ruoyi.ss.order.domain.vo.ReservedTimePeriod;
import com.ruoyi.ss.order.mapper.OrderMapper;
import com.ruoyi.ss.order.service.IOrderConverter;
import com.ruoyi.ss.order.service.IOrderService;
import com.ruoyi.ss.order.service.IOrderValidator;
import com.ruoyi.ss.orderOper.service.IOrderOperService;
import com.ruoyi.ss.pay.service.IWxPayService;
import com.ruoyi.ss.payBill.domain.PayBillVO;
import com.ruoyi.ss.payBill.service.PayBillService;
import com.ruoyi.ss.product.service.IProductService;
import com.ruoyi.ss.reconciliation.domain.ReconciliationQuery;
import com.ruoyi.ss.reconciliation.domain.ReconciliationVO;
import com.ruoyi.ss.reconciliation.domain.enums.ReconciliationDateChannelType;
import com.ruoyi.ss.reconciliation.service.IReconciliationService;
import com.ruoyi.ss.refund.domain.Refund;
import com.ruoyi.ss.refund.domain.RefundQuery;
import com.ruoyi.ss.refund.service.IRefundService;
import com.ruoyi.ss.room.domain.Room;
import com.ruoyi.ss.room.domain.RoomQuery;
import com.ruoyi.ss.room.service.IRoomAssembler;
import com.ruoyi.ss.room.service.IRoomService;
import com.ruoyi.ss.store.domain.StoreVO;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.ss.user.domain.UserQuery;
import com.ruoyi.ss.user.domain.UserVO;
import com.ruoyi.ss.user.service.IUserService;
import com.ruoyi.ss.withdraw.domain.WithdrawQuery;
import com.ruoyi.ss.withdraw.service.IWithdrawService;
import com.ruoyi.system.domain.query.IndexChartQuery;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.domain.vo.admin.OrderInCome;
import com.ruoyi.system.domain.vo.admin.PlatformInCome;
import com.ruoyi.system.domain.vo.admin.RechargeWithdrawal;
import com.ruoyi.system.domain.vo.admin.UserBalanceData;
import com.ruoyi.system.service.ISysConfigService;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

import static com.ruoyi.common.constant.ServiceConstants.*;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;

/**
 * 订单Service业务层处理
 *
 * @author qzz
 * @date 2024-09-19
 */
@Service
public class OrderServiceImpl implements IOrderService
{

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private IWxPayService wxPayService;

    @Autowired
    private IFeeRuleService feeRuleService;

    @Resource
    private IOrderConverter orderConverter;

    @Resource
    private IOrderValidator orderValidator;

    @Autowired
    private ISysConfigService configService;

    @Resource
    private IUserService userService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private IRefundService refundService;

    @Autowired
    private IOrderOperService rlOrderOperService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private IOrderOperService orderOperService;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private IDividendDetailService dividendDetailService;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private IProductService productService;

    @Autowired
    private IRoomAssembler roomAssembler;

    @Autowired
    private PayBillService paymentService;

    @Autowired
    private IReconciliationService reconciliationService;

    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.signName}")
    private String signName;

    @Value("${aliyun.templateCode3}")
    private String templateCode3;

    @Autowired
    private IStoreService storeService;

    @Autowired
    private IRefundService etRefundService;

    @Autowired
    private IUserBalanceService userBalanceService;

    @Autowired
    private IIntentionService intentionService;

    @Autowired
    private IWithdrawService withdrawService;

    @Autowired
    private ICleanService cleanService;


    /**
     * 查询订单
     *
     * @param orderId 订单主键
     * @return 订单
     */
    @Override
    public OrderVO selectRlOrderByOrderId(Long orderId)
    {
        return orderMapper.selectRlOrderByOrderId(orderId);
    }

    /**
     * 查询订单
     *
     * @param orderNo 订单号
     * @return 订单
     */
    @Override
    public OrderVO selectRlOrderByOrderNo(String orderNo)
    {
        return orderMapper.selectRlOrderByOrderNo(orderNo);
    }

//    /**
//     * 第三方订单号
//     *
//     * @param outTradeNo 订单号
//     * @return 订单
//     */
//    @Override
//    public OrderVO selectRlOrderByOutTradeNo(String outTradeNo)
//    {
//        return orderMapper.selectRlOrderByOutTradeNo(outTradeNo);
//    }


    /**
     * 查询订单
     *
     * @param orderNo 订单号
     * @return 订单
     */
    @Override
    public OrderVO getOrderInfoByOrderNo(String orderNo)
    {
        OrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
        if(ObjectUtil.isNull(order)){
            throw new ServiceException("订单不存在");
        }
        /** 组装信息*/
        assembleInfo(order);
        return order;
    }

    private void assembleInfo(OrderVO order) {
        /** 大门的在线状态*/
        updateGateOnlineStatus(order);

        /** 套餐*/
        FeeRuleVO feeRule = feeRuleService.selectEFeeRuleByRuleId(order.getRuleId());
        order.setRule(feeRule);

        /** 店铺地址*/
        StoreVO storeVO = storeService.selectEStoreByStoreId(order.getStoreId());
        if(storeVO != null){
            order.setStoreAddress(storeVO.getAddress());
            order.setGateUnlockMode(storeVO.getUnlockMode());
            order.setGateUnlockTime(storeVO.getUnlockTime());
        }

        /** 退款列表 */
        PayBillVO payBillVO = paymentService.selectPayBillByPayId(order.getPayId());
        if(!ObjectUtil.isNull(payBillVO)){
            RefundQuery refund = new RefundQuery();
            refund.setPayId(order.getPayId());
            List<Refund> refunds = etRefundService.selectEtRefundList(refund);
            order.setRefunds(refunds);
        }
    }

    /**
     * 查询订单列表
     *
     * @param rlOrder 订单
     * @return 订单
     */
    @Override
    @DataScope(merchantAlias = "m", userAlias = "u")
    public List<OrderVO> selectRlOrderList(OrderQuery rlOrder)
    {
        return orderMapper.selectRlOrderList(rlOrder);
    }

    /**
     * 查询订单列表  不待数据隔离
     *
     * @param rlOrder 订单
     * @return 订单
     */
    @Override
    public List<OrderVO> selectRlOrderListNoIsolate(OrderQuery rlOrder)
    {
        return orderMapper.selectRlOrderList(rlOrder);
    }

    /**
     * 查询所有订单列表
     *
     * @param rlOrder 订单
     * @return 订单
     */
    @Override
    public List<OrderVO> selectAllRlOrderList(OrderQuery rlOrder)
    {
        return orderMapper.selectAllRlOrderList(rlOrder);
    }

    /**
     * 新增订单
     *
     * @param rlOrder 订单
     * @return 结果
     */
    @Override
    public int insertRlOrder(OrderQuery rlOrder)
    {
        rlOrder.setCreateTime(DateUtils.getNowDate());
        return orderMapper.insertRlOrder(rlOrder);
    }

    /**
     * 修改订单
     *
     * @param rlOrder 订单
     * @return 结果
     */
    @Override
    public int updateRlOrder(Order rlOrder)
    {
        return orderMapper.updateRlOrder(rlOrder);
    }

    /**
     * 根据订单号修改订单
     *
     * @param rlOrder 订单
     * @return 结果
     */
    @Override
    public int updateRlOrderByOrderNo(Order rlOrder)
    {
        return orderMapper.updateRlOrderByOrderNo(rlOrder);
    }


    /**
     * 批量删除订单
     *
     * @param orderIds 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteRlOrderByOrderIds(Long[] orderIds)
    {
        return orderMapper.deleteRlOrderByOrderIds(orderIds);
    }

    /**
     * 删除订单信息
     *
     * @param orderId 订单主键
     * @return 结果
     */
    @Override
    public int deleteRlOrderByOrderId(Long orderId)
    {
        return orderMapper.deleteRlOrderByOrderId(orderId);
    }

    /**
     * 下单
     * 1. 创建订单
     * 2. 预支付
     * 3.
     *
     * @param order 订单对象
     * @return 结果
     */
    @Override
    public PrepayResponseVO createOrder(OrderDTO order) {
        OrderBO orderBO = orderConverter.toOrderBO(order);
        return getPrepayResponseVO(orderBO);
    }

    /**
     * 续单
     *
     * @param reOrder 续单对象
     * @return 结果
     */
    @Override
    public PrepayResponseVO reOrder(ReOrderDTO reOrder) {
        OrderBO orderBO = orderConverter.toOrderBO(reOrder);
        return getPrepayResponseVO(orderBO);
    }

//    /**
//     * 充值订单
//     */
//    @Override
//    public PrepayResponseVO topUp(TopUpOrderDTO topUpOrder){
//        OrderBO orderBO = orderConverter.toOrderBO(topUpOrder);
//        return getPrepayResponseVO(orderBO);
//    }

    /**
     * 货柜订单
     */
    @Override
    public PrepayResponseVO productOrder(ProductDTO product){
        OrderBO orderBO = orderConverter.toOrderBO(product);
        return getPrepayResponseVO(orderBO);
    }

    @NotNull
    private PrepayResponseVO getPrepayResponseVO(OrderBO orderBO) {
        Long roomId = ORDER_TYPE_REORDER.equals(orderBO.getReType())
                ? orderBO.getOriginalOrder().getRoomId()
                : orderBO.getParams().getRoomId();
        String type = orderBO.getType();
        RedisLockKey key ;
        String desc = "当前预定该包间人数较多，请稍后再试";
        // 加锁
        if(type.equals(ORDER_TYPE_TEA) || type.equals(ORDER_TYPE_MAHJONG) || type.equals(ORDER_TYPE_BILLIARDS)){
            key = RedisLockKey.CREATE_ORDER;
        }else{
            key = RedisLockKey.PRODUCT_ORDER;
            desc = "当前购买该商品人数较多";
        }
        ServiceUtil.assertion(!redisLock.lock(key, roomId), desc);
        try {
            // bo转order订单
            Order order = parseToOrder(orderBO);
            orderBO.setOrder(order);

            List<ReservedTimePeriod> timePeriods = roomAssembler.getReservedTimePeriods(roomId, new Date());//获取到当前时间到未来24小时内的已预约时间段
            if(orderBO.getReType().equals(ORDER_TYPE_RESERVE)){
                ServiceUtil.assertion(isOverlap(timePeriods,order.getReserveStartTime(),order.getReserveEndTime()), "该房间在预约时段内存在订单");
            }else{
                ServiceUtil.assertion(isOverlap(timePeriods,orderBO.getOriginalOrder().getReserveEndTime(),order.getReserveEndTime()), "该房间在续单时间内存在订单");
            }

            // 组装分成list
            List<DividendDetail> dividendList = assemblerDividendList(order, orderBO);

            PrepayResponseVO responseVO = new PrepayResponseVO();
            Boolean execute = transactionTemplate.execute(e -> {
                logger.info("=================【下单】==================");
                // 保存订单
                int i = orderMapper.insertRlOrder(order);
                ServiceUtil.assertion(i < 1, "下单失败：保存订单失败");

                // 插入分成
                insertDividend(dividendList);

                // 创建支付订单并返回支付
                PrepayWithRequestPaymentResponse response = wxPayService.prepayWithRequestPayment(orderBO);
                responseVO.setResponse(response);
                responseVO.setOrderNo(order.getOrderNo());

                // 发短信给代理商
//            YPMsgUtils.sendPlaceOrderMsg(orderNo,rlAgentVO.getPhone(),order.getPhone());
                return Boolean.TRUE;
            });
            if(Boolean.FALSE.equals(execute))throw new ServiceException("【下单】失败");
            return responseVO;
        } finally {
            // 解锁
            redisLock.unlock(key, roomId);
        }
    }

    /**
     * 判断给定的时间段是否与任何已预定的时间段重叠
     *
     * @param reservedTimePeriods 已预定的时间段列表
     * @param checkStartTime      需要检查的开始时间
     * @param checkEndTime        需要检查的结束时间
     * @return 是否存在重叠
     */
    public boolean isOverlap(List<ReservedTimePeriod> reservedTimePeriods, Date checkStartTime, Date checkEndTime) {
        if (reservedTimePeriods == null || reservedTimePeriods.isEmpty()) {
            return false;
        }

        for (ReservedTimePeriod rtp : reservedTimePeriods) {
            try {
                Date existingStart = sdf.parse(rtp.getStartTime());
                Date existingEnd = sdf.parse(rtp.getEndTime());

                // 检查时间段是否有重叠
                if ((checkStartTime.before(existingEnd) && checkEndTime.after(existingStart)) ||
                        (checkEndTime.after(existingStart) && checkStartTime.before(existingEnd))) {
                    return true; // 存在重叠
                }
            } catch (Exception e) {
                e.printStackTrace(); // 处理日期格式转换异常
            }
        }

        return false; // 没有重叠
    }

    /**
     * 组装分成list
     */
    private List<DividendDetail> assemblerDividendList(Order order, OrderBO bo) {
        // 组装分账list
        BigDecimal platformServiceFee = order.getPlatformServiceFee();
        /**
         * 1. 获取到所有需要分账的用户
         * 2. 遍历新建分账对象
         * 3. 分账剩余比例分配给商户
         * */
        BigDecimal dividendTotalFee = order.getPayFee().subtract(platformServiceFee);// 分账总金额
        BigDecimal dividendResidualProportion = new BigDecimal(100);// 分账剩余比例
        List<DividendDetail> dividends = new ArrayList<>();
        List<User> dividendUsers = userService.selectDividendUserList(bo.getMerchant().getUserId());

        // 校验总分账比例不能个大于100%
        orderValidator.checkDividendProportions(dividendUsers);

        // 合伙人分账
        for (User dividendUser : dividendUsers){
            DividendDetail dividendDetail = new DividendDetail();
            dividendDetail.setPartnerId(dividendUser.getUserId());
            dividendDetail.setPartnerName(dividendUser.getUserName());
            dividendDetail.setPartnerPhone(dividendUser.getPhonenumber());
            dividendDetail.setPartnerType(dividendUser.getUserType());
            dividendDetail.setOrderNo(order.getOrderNo());
            dividendDetail.setTotalAmount(dividendTotalFee);
            dividendDetail.setStatus(DIVIDEND_STATUS_UNPAID);
            dividendDetail.setDividendProportion(dividendUser.getDividendProportion());

            // 扣除当前用户的分账比例后更新剩余比例
            dividendResidualProportion = dividendResidualProportion.subtract(dividendUser.getDividendProportion());

            dividends.add(dividendDetail);
        }
        // 商户分账
        DividendDetail dividendDetail = new DividendDetail();
        dividendDetail.setPartnerId(bo.getMerchant().getUserId());
        dividendDetail.setPartnerName(bo.getMerchant().getUserName());
        dividendDetail.setPartnerPhone(bo.getMerchant().getPhonenumber());
        dividendDetail.setPartnerType(bo.getMerchant().getUserType());
        dividendDetail.setOrderNo(order.getOrderNo());
        dividendDetail.setTotalAmount(dividendTotalFee);
        dividendDetail.setStatus(DIVIDEND_STATUS_UNPAID);
        dividendDetail.setDividendProportion(dividendResidualProportion);
        dividends.add(dividendDetail);
        return dividends;
    }

    /**
     * 1. 批量插入分成记录
     * 创建分成明细
     * 2. 在支付后更新分成的金额、状态、实际支付金额
     *
     */
    private void insertDividend(List<DividendDetail> dividendList) {
        if(!dividendList.isEmpty()){
            dividendList.forEach(e -> {
                int i = dividendDetailService.insertRlDividendDetail(e);
                ServiceUtil.assertion(i < 1, "创建分成明细失败");
            });
        }
    }

    // 生成订单号
    private String generateOrderNo(String type,String reType) {
        boolean isReorder = ORDER_TYPE_REORDER.equals(reType);
        OrderType orderType = OrderType.fromType(type);
        String orderNoPrefix = orderType.getPrefix(isReorder);
        return IdUtils.getOrderNo(orderNoPrefix);
    }

    // 转换为订单所需的数据
    private Order parseToOrder(OrderBO orderBO) {
        // 校验
        ServiceUtil.assertion(orderValidator.preAddOrder(orderBO));

        Order order = new Order();
        String orderNo = generateOrderNo(orderBO.getType(), orderBO.getReType());

        Date reserveStartTime;
        String payType;
        if(orderBO.getReType().equals(ORDER_TYPE_RESERVE)){// 预定单
            reserveStartTime = orderBO.getParams().getReserveStartTime();
            payType = orderBO.getParams().getPayType();
            setOrderInfo(orderBO, order, reserveStartTime);
            order.setPlatformServiceFee(getPlatformServiceFee(orderBO,order.getPayFee()));
        }else if(orderBO.getReType().equals(ORDER_TYPE_REORDER)){ // 续单
            reserveStartTime = orderBO.getOriginalOrder().getReserveStartTime();
            payType = orderBO.getReOrderDTO().getPayType();
            setOrderInfo(orderBO, order, reserveStartTime);
            order.setPlatformServiceFee(getPlatformServiceFee(orderBO,order.getPayFee()));
            order.setOriginalOrderNo(orderBO.getOriginalOrder().getOrderNo());
        }else{
            throw new ServiceException("非法的订单类型");
        }

//        if(orderBO.getType().equals(ORDER_TYPE_CONTAINER)) {// 货柜订单
//            order.setTotalFee(orderBO.getProduct().getPrice());
//            order.setPayFee(orderBO.getProduct().getPrice());
//            order.setPlatformServiceFee(getPlatformServiceFee(orderBO, order.getPayFee()));
//            order.setProductId(orderBO.getProduct().getProductId());
//            order.setProductName(orderBO.getProduct().getName());
//            order.setProductPicture(orderBO.getProduct().getPicture());
//        }

        //基本信息
        order.setCreateTime(DateUtils.getNowDate());
        order.setOrderNo(orderNo);
        order.setPayType(payType);
        order.setPaid(ORDER_PAY_STATUS_NON_PAYMENT);
        order.setType(orderBO.getType());
        order.setStatus(ORDER_STATUS_TO_BE_PAID);
        order.setReType(orderBO.getReType());

        //用户
        order.setUserId(orderBO.getUser().getUserId());
        order.setUserName(orderBO.getUser().getUserName());
        order.setPhone(orderBO.getUser().getPhonenumber());
        order.setRealName(orderBO.getUser().getRealName());

        // 商户
        order.setMerchantId(orderBO.getMerchant().getUserId());
        order.setMerchantName(orderBO.getMerchant().getUserName());

        // 店铺
        order.setStoreId(orderBO.getStore().getStoreId());
        order.setStoreName(orderBO.getStore().getName());
        order.setCityId(orderBO.getStore().getCityId());
        order.setWifi(orderBO.getRoom().getWifi());
        order.setWifiPassword(orderBO.getRoom().getWifiPassword());
        order.setLng(orderBO.getStore().getLng());
        order.setLat(orderBO.getStore().getLat());
        order.setManagerPhone(orderBO.getStore().getManagerPhone());

        // 取消时间
        String configByKey = configService.selectConfigByKey("rl.order.auto.cancel");
        order.setAutoCancelTime(DateUtils.getTimeAfterXMinutes(order.getCreateTime(),Integer.parseInt(configByKey)));
        // 校验
        ServiceUtil.assertion(orderValidator.afterAddOrder(order));
        return order;
    }

    private static @NotNull BigDecimal getPlatformServiceFee(OrderBO orderBO,BigDecimal payFee) {
        BigDecimal platformServiceFee;
        platformServiceFee = orderBO.getMerchant().getServiceFeeProportion()
            .multiply(payFee)
            .setScale(2, RoundingMode.HALF_UP);// 服务费 = 48 * 0.05 = 2.4
        return platformServiceFee;
    }

    private static void setOrderInfo(OrderBO orderBO, Order order, Date reserveStartTime) {
        FeeRuleVO feeRule = orderBO.getFeeRule();

        //套餐
        order.setRuleId(feeRule.getRuleId());
        order.setMode(feeRule.getMode());
        order.setHours(feeRule.getHours());
        order.setPrice(feeRule.getPrice());
        order.setExplain(feeRule.getExplain());

        //支付渠道
        order.setPayChannel(orderBO.getChannel().getChannelId());
        order.setChannelName(orderBO.getChannel().getName());

        // 价格
        /** 根据套餐计算价格 */
        if(feeRule.getMode().equals(ServiceConstants.CHARGE_MODE_HOURLY)){
            order.setTotalFee(feeRule.getDeposit());
            order.setDeposit(feeRule.getDeposit());
            order.setRefundDuration(feeRule.getRefundDuration());
        }else{
            order.setTotalFee(feeRule.getPrice());
        }
        order.setPayFee(order.getTotalFee());

        /** 如果是预定订单，根据预约开始时间计算出预约结束时间
         * 如果是续费订单，预约开始时间是原订单的预约开始时间 */
        // dto
        order.setReserveStartTime(reserveStartTime);
        if(ORDER_TYPE_RESERVE.equals(orderBO.getReType())){
            order.setReserveEndTime(DateUtils.getTimeAfterXUnit(reserveStartTime,feeRule.getHours(),"hours"));
        }else{
            Date reserveEndTime = orderBO.getOriginalOrder().getReserveEndTime();
            order.setReserveEndTime(DateUtils.getTimeAfterXUnit(reserveEndTime,feeRule.getHours(),"hours"));
        }
        order.setDuration(DateUtils.timeDifferenceInHours(reserveStartTime, order.getReserveEndTime()));

        if(ObjectUtil.isNotNull(orderBO.getGate())){
            // 大门
            order.setGateMac(orderBO.getGate().getMac());
            order.setGateMac2(orderBO.getGate().getMac2());
            order.setGateSn(orderBO.getGate().getSn());
            order.setGateId(orderBO.getGate().getDeviceId());
        }

        //房间
        if(orderBO.getType2().equals(ROOM_TYPE2_LOBBY_DEVICE)){
            order.setEquipmentId(orderBO.getEquipment().getEquipmentId());
            order.setEquipmentType(orderBO.getEquipment().getType());
            order.setEquipmentName(orderBO.getEquipment().getName());
        }
        order.setRoomId(orderBO.getRoom().getRoomId());
        order.setRoomName(orderBO.getRoom().getRoomName());
        order.setRoomType(orderBO.getRoom().getType());
        order.setRoomType2(orderBO.getRoom().getType2());
        if(!orderBO.getRoom().getPictures().isEmpty()){
            order.setPicture(orderBO.getRoom().getPictures().get(0));
        }
        order.setRoomMac(orderBO.getDevice().getMac());
        order.setRoomMac2(orderBO.getDevice().getMac2());
        order.setRoomSn(orderBO.getDevice().getSn());
    }

//    /**
//     * 扫码绑定车辆
//     */
//    @Override
//    public int bandDevice(String orderNo, String sn) {
//        OrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
//        if(order == null){
//            throw new RuntimeException("订单不存在");
//        }
//        OrderVO order1 = getInProgressOrder(sn);
//        if(ObjectUtil.isNotNull(order1)){
//            throw new RuntimeException("该车辆【"+sn+"】有进行中的订单：");
//        }
//        Boolean execute = transactionTemplate.execute(e -> {
//            logger.info("=================【扫码绑定车辆】==================");
//            Order rlOrder = new Order();
//            rlOrder.setOrderNo(orderNo);
//            rlOrder.setStatus(ServiceConstants.ORDER_STATUS_IN_USE);
////            rlOrder.setPickupTime(DateUtils.getNowDate());
////            Date expiryTime = DateUtils.getTimeAfterXUnit(DateUtils.getNowDate(), order.getNum(), order.getRentalUnit());
////            rlOrder.setExpiryTime(expiryTime);
//            int i = orderMapper.updateRlOrderByOrderNo(rlOrder);
//            if(i > 0){
//                /** 更新设备状态 */
////                EDeviceQuery rlDevice = new EDeviceQuery();
////                rlDevice.setSn(sn);
////                rlDevice.setStatus(ServiceConstants.VEHICLE_STATUS_TEMPORARILY_LOCK);
////                deviceService.updateEDeviceBySn(rlDevice);
//            }
//            return Boolean.TRUE;
//        });
//        if(Boolean.FALSE.equals(execute))throw new ServiceException("扫码绑定车辆失败");
//        return 1;
//    }

//    /**
//     * 用户扫码绑定车辆
//     *  1. 校验sn是否存在
//     *  2. 绑定车辆,在车辆中添加用户id
//     */
//    @Override
//    public int userBandDevice(Long userId, String sn) {
////        EDevice device = deviceService.selectEDeviceBySn(sn);
////        if(device == null){
////            throw new ServiceException("设备不存在:"+sn);
////        }
////        if(device.getMerchantId() != null && device.getMerchantId() != 0){
////            throw new ServiceException("该车辆已绑定用户");
////        }
////        Boolean execute = transactionTemplate.execute(e -> {
////            logger.info("=================【用户扫码绑定车辆】==================");
////            EDeviceQuery rlDevice = new EDeviceQuery();
////            rlDevice.setSn(sn);
////            rlDevice.setMerchantId(userId);
////            deviceService.updateEDeviceBySn(rlDevice);
////            return Boolean.TRUE;
////        });
////        if(Boolean.FALSE.equals(execute))throw new ServiceException("【用户扫码绑定车辆】失败");
//        return 1;
//    }

//        RlOrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
//        if(order == null){
//            throw new RuntimeException("订单不存在");
//        }
//        if(StrUtil.isNotBlank(order.getSn())){
//            throw new RuntimeException("该订单已绑定车辆："+order.getSn());
//        }
//        RlOrderVO order1 = getInProgressOrder(sn);
//        if(ObjectUtil.isNotNull(order1)){
//            throw new RuntimeException("该车辆【"+sn+"】有进行中的订单：");
//        }
//        Boolean execute = transactionTemplate.execute(e -> {
//            logger.info("=================【扫码绑定车辆】==================");
//            RlOrder rlOrder = new RlOrder();
//            rlOrder.setOrderNo(orderNo);
//            rlOrder.setSn(sn);
//            rlOrder.setStatus(ServiceConstants.ORDER_STATUS_IN_USE);
//            rlOrder.setPickupTime(DateUtils.getNowDate());
//            Date expiryTime = DateUtils.getTimeAfterXUnit(DateUtils.getNowDate(), order.getNum(), order.getRentalUnit());
//            rlOrder.setExpiryTime(expiryTime);
//            int i = orderMapper.updateRlOrderByOrderNo(rlOrder);
//            if(i > 0){
//                /** 更新设备状态 */
//                EDevice rlDevice = new EDevice();
//                rlDevice.setSn(sn);
//                rlDevice.setStatus(ServiceConstants.VEHICLE_STATUS_TEMPORARILY_LOCK);
//                deviceService.updateEDeviceBySn(rlDevice);
//            }
//            return Boolean.TRUE;
//        });
//        if(!execute)throw new ServiceException("扫码绑定车辆失败");
//        return 1;
//    }

    /**
     * 续单
     * 到期时间
     * 1.  根据原来的订单号，写入新的订单
     * 2.  续单订单标记类型
     * 3.
     */
    @Override
    public PrepayResponseVO relet(OrderQuery query) {
        OrderVO order = orderMapper.selectRlOrderByOrderNo(query.getOrderNo());
        if(ObjectUtil.isNull(order)){
            throw new RuntimeException("订单【"+query.getOrderNo()+"】不存在");
        }
        OrderQuery orderQuery = new OrderQuery();
        BeanUtils.copyBeanProp(orderQuery,order);
        /** 原订单已经到期  续单订单的到期时间是根据原订单的到期时间算出来的 */
//        Date nowDate = DateUtils.getNowDate();
//        if (order.getExpiryTime().before(nowDate)) {
//            /** 到期后先计算逾期费用，保存在订单中，在还车时一起结算 */
//            EOrder updateOrder = new EOrder();
//            updateOrder.setOrderId(order.getOrderId());
//            BigDecimal overdueFee= BigDecimal.ZERO;
//            if(ObjectUtil.isNull(order.getExpiryTime())){
//                throw new ServiceException("【续单】订单没有到期时间");
//            }
////            if (order.getExpiryTime().before(DateUtils.getNowDate())) {
////                overdueFee = deviceService.computeOverdueFee(order, updateOrder);
////            }
//            updateOrder.setOverdueFee(overdueFee);
//            int i = updateRlOrder(updateOrder);
//            if(i==0){
//                throw new ServiceException("更新订单状态失败");
//            }
//        }
        orderQuery.setOriginalOrderNo(query.getOrderNo());
        orderQuery.setRuleId(query.getRuleId());
        String newOrderNo = IdUtils.getOrderNo("xz");
//        getPrepayResponseVO(orderQuery,newOrderNo,ServiceConstants.ORDER_TYPE_RELET,SecurityUtils.getUserId())
        return null;
    }

    /**
     * 订单取消
     * 1.  根据订单号查询订单
     * 2.  判断订单状态是否为已支付，未支付直接结束订单，已支付继续
     * 3.  订单时间已到不能取消
     * 4.  时间在120分钟内收取违约金20%，订单取消
     *      扣除订单金额的20%，剩余订单金额原路退回
     * 5.  时间在120分钟外不收取违约金，订单取消
     * 6.  订单取消后，订单状态为已取消
     */
    @Override
    public Boolean orderCancel(String orderNo) {
        ServiceUtil.assertion(StrUtil.isBlank(orderNo),"订单号不能为空");
        OrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
        ServiceUtil.assertion(order == null,"订单不存在");

        PayBillVO payBillVO = paymentService.selectPayBillByPayId(order.getPayId());
        // todo  刷新支付结果
        Boolean execute = transactionTemplate.execute(e -> {
            logger.info("=================【订单取消】==================");
            if(ORDER_PAY_STATUS_PAID.equals(order.getPaid())){
                // 如果订单已支付则发起退款
                UserVO userVO = userService.selectUserById(order.getUserId());
                ServiceUtil.assertion(userVO == null,"用户不存在");
                ServiceUtil.assertion(!Objects.equals(order.getUserId(), getUserId()),"非本人订单不能取消");
                Integer cleanDuration = userVO.getAgoCancel();//取消时长（分钟）
                BigDecimal penalty = userVO.getPenalty();// 违约金比例
                Date reserveStartTime = order.getReserveStartTime();// 预约开始时间
                // 根据预约开始时间判断，如果当前时间在取消时长（分钟）范围外，则不收违约金，直接取消订单
                // 如果当前时间在取消时长（分钟）范围内，并且为超过预约开始时间，则计算违约金，按照订单金额乘以违约金比例,并将剩余订单金额按渠道原路退回
                // 如果当前时间已经超过预约开始时间，则不能取消订单
                Date nowDate = DateUtils.getNowDate();
                BigDecimal refundAmount = BigDecimal.ZERO;
                BigDecimal penaltyAmount = BigDecimal.ZERO;
                int i = DateUtils.timeDifferenceInMinutes(reserveStartTime, nowDate);
                if (i > cleanDuration) {// 在取消时长外，则不收违约金，直接取消订单
                    logger.info("当前时间在取消时长外，则不收违约金，直接取消订单");
                }else if (i <= 0) {
                    // 如果当前时间已经超过预约开始时间，则不能取消订单
                    throw new RuntimeException("【订单取消】已超过预约开始时间，不能取消订单");
                } else{//在取消时长内
                    // 如果当前时间在取消时长（分钟）范围内，并且未超过预约开始时间，则计算违约金
                    penaltyAmount = order.getPayFee().multiply(penalty).setScale(2, RoundingMode.HALF_UP);
                    refundAmount = order.getPayFee().subtract(penaltyAmount);
                    logger.info("需支付违约金：{}，退款金额：{}", penaltyAmount, refundAmount);
                }
                if(refundAmount.compareTo(BigDecimal.ZERO) > 0){
                    String refNo = IdUtils.getOrderNo("ref");
                    wxPayService.refund(order,"订单取消，扣除违约金："+penaltyAmount+",退还剩余金额："+refundAmount, refundAmount,refNo,payBillVO.getPayNo());
                }
            }
            /* 更新订单状态 */
            orderCancelUpdate(order,orderNo, "1",null,null,null);
            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("订单取消失败");
        return true;
    }

    /**
     * 订单结束
     */
    @Override
    public Boolean orderEnd(String orderNo) {
        ServiceUtil.assertion(StrUtil.isBlank(orderNo),"订单号不能为空");
        OrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
        ServiceUtil.assertion(order == null,"订单不存在");
        ServiceUtil.assertion(!ORDER_STATUS_IN_USE.equals(order.getStatus()),"订单状态异常: 非使用中状态");
        ServiceUtil.assertion(ORDER_PAY_STATUS_NON_PAYMENT.equals(order.getPaid()),"订单未支付，请先支付！");
        // 最低消费时间
        FeeRuleVO feeRuleVO = feeRuleService.selectEFeeRuleByRuleId(order.getRuleId());
        ServiceUtil.assertion(feeRuleVO == null,"套餐不存在");
        BigDecimal minHours = feeRuleVO.getMinHours();
         if(minHours != null){
            int actualHours = DateUtils.timeDifferenceInHours(DateUtils.getNowDate(), order.getReserveStartTime());// 实际时长
            ServiceUtil.assertion(actualHours < minHours.intValue(), "订单未达到最低消费时长，不能结束");
        }

        Boolean execute = transactionTemplate.execute(e -> {
            if(order.getMode().equals(CHARGE_MODE_HOURLY)){
                // todo  刷新支付结果
                logger.info("=================【订单结束】==================");
                // 当前时间在预约开始时间之前，则不能结束订单
                ServiceUtil.assertion(DateUtils.getNowDate().before(order.getReserveStartTime()), "订单还未开始，不能结束");
                int i = DateUtils.timeDifferenceInHoursWithCeil(order.getReserveStartTime(), DateUtils.getNowDate());
                ServiceUtil.assertion( i == 0, "订单还未开始，不能结束");

                BigDecimal deposit = order.getDeposit();
                BigDecimal payFee = order.getPrice().multiply(new BigDecimal(i));
                BigDecimal refundAmount = deposit.subtract(payFee);

                if(deposit.compareTo(BigDecimal.ZERO) != 0 && refundAmount.compareTo(BigDecimal.ZERO) > 0){
                    // todo 延时退款 记录退款的时间 延时3分钟
                    order.setRefundTime(DateUtils.getTimeAfterXMinutes(DateUtils.getNowDate(),order.getRefundDuration()));
                }
                order.setIsSendMsg(true);
                /* 更新订单状态 */
                String format = StrUtil.format("订单结束，押金:{},已使用金额：{}，退还剩余金额：{}", deposit, payFee, refundAmount);
                logger.info("=================【订单结束】==================format【{}】",format);
                orderCancelUpdate(order,orderNo, "2",payFee, refundAmount,format);
            }else{
                //非小时计费的套餐只是改变状态，不退款
                orderCancelUpdate(order,orderNo, "2",null,null,null);
            }

            /* 通知保洁  */
            String merchantPhone = order.getMerchantPhone();
            YPMsgUtils.sendClearMsg(order.getRoomName(),merchantPhone);

            Clean clean = cleanService.buildClean(order);
            int i = cleanService.insertEClean(clean);
            ServiceUtil.assertion(i==0,"生成保洁订单失败");

            /* 更新房间状态 */
            Room room = new Room();
            room.setStatus(ROOM_STATUS_FREE);
            room.setRoomId(order.getRoomId());
            int i1 = roomService.updateERoom(room);
            ServiceUtil.assertion(i1 == 0,"【订单结束】更新房间状态失败");

            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("订单结束失败");
        return true;
    }

    /*
    *  usedAmount 已使用金额
    *  refundAmount  退款金额
    * */
    private void orderCancelUpdate(OrderVO order,String orderNo, String type,BigDecimal payFee, BigDecimal refundAmount,String depositRefundDesc) {
        /** 更新订单状态 */
        Order rlOrder = new Order();
        rlOrder.setOrderNo(orderNo);
        String desc;
        String operType;
        if(type.equals("1")){
            rlOrder.setStatus(ORDER_STATUS_USER_CANCE);
            desc = "用户取消订单";
            operType = ORDER_OPERATION_USER_CANCEL;
        }else{// 用户结束订单
            rlOrder.setStatus(ORDER_STATUS_USER_FINISH);
            desc = "用户结束订单";
            operType = ORDER_OPERATION_RETURN_END;
            rlOrder.setRefundTime(order.getRefundTime());
            rlOrder.setDepositRefund(refundAmount);
            rlOrder.setDepositRefundDesc(depositRefundDesc);
            rlOrder.setPayFee(payFee);
        }
        int i = orderMapper.updateRlOrderByOrderNo(rlOrder);
        ServiceUtil.assertion(i == 0, "取消订单失败：更新订单状态失败");

        /** todo 更新支付订单  关闭所有的支付订单 */

        /** 记录订单履历 */
        boolean b = orderOperService.recordOrderHistory(orderNo, operType,
                order.getStatus(), rlOrder.getStatus(), order.getPayFee(), BigDecimal.ZERO, order.getUserId(), order.getPhone(), desc);
        ServiceUtil.assertion(!b, "取消订单失败：记录订单履历失败");
    }

    /**
     * 车损扣款
     */
    @Override
    public Boolean deductMoney(BigDecimal money, String orderNo) {
        Order rlOrder = new Order();
        rlOrder.setOrderNo(orderNo);
        int i = orderMapper.updateRlOrderByOrderNo(rlOrder);
        /** 记录订单履历 */
        OrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
//        if(!orderOperService.recordOrderHistory(orderNo,ServiceConstants.ORDER_OPERATION_DEDUCTION,
//                order.getStatus(),order.getStatus(),order.getPayFee(),order.getPayFee(),order.getUserId(),order.getPhone(),
//                "车损扣款：扣款金额："+money+"，实际押金退款："+order.getDeposit()+"-"+money)){
//            throw new ServiceException("【车损扣款】更新订单信息失败");
//        }
        return i>0;
    }

//    /**
//     * 商家还车
//     *
//     */
//    @Override
//    public Boolean merchantReturn(String orderNo) {
//        EOrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
//        if(ObjectUtil.isNull(order)){
//            throw new ServiceException("订单不存在");
//        }
////        BigDecimal deposit = order.getDeposit();
////        BigDecimal overdueFee = order.getOverdueFee();
////        BigDecimal deductionAmount = order.getDeductionAmount();
////        BigDecimal remainingDeposit = deposit.subtract(overdueFee).subtract(deductionAmount);
//        if(!ServiceConstants.ORDER_PAY_STATUS_PAID.equals(order.getPaid())){
//          throw new ServiceException("订单未支付，不能还车", HttpStatus.ERROR);
//        }
//        if(!(ServiceConstants.ORDER_STATUS_TO_BE_AUDITED.equals(order.getStatus()) || ServiceConstants.ORDER_STATUS_IN_USE.equals(order.getStatus()))){
//            throw new ServiceException("订单非待审核或骑行中状态，不能还车", HttpStatus.ERROR);
//        }
//        Boolean execute = transactionTemplate.execute(e -> {
//            /** 1.更新订单信息*/
//            updateOrderStatus(orderNo);
//            /** 2.更新车辆状态*/
////            updateDeviceInfo(order.getSn());
//            /** 3.记录订单履历*/
//            if(!orderOperService.recordOrderHistory(orderNo,ServiceConstants.ORDER_OPERATION_RETURN_END,
//                    order.getStatus(),order.getStatus(),order.getPayFee(),order.getPayFee(),order.getUserId(),order.getPhone(),"已退款：-"+remainingDeposit+"元")){
//                throw new ServiceException("【记录订单履历失败】");
//            }
//            if(remainingDeposit.compareTo(BigDecimal.ZERO) > 0){
//                /** 4.执行退还剩余押金操作*/
//                /** 5.新增一条退款记录*/
//                String outRefundNo = saveDepositRefundObj(order, remainingDeposit);
//                logger.info("【商家还车】退还剩余押金："+remainingDeposit);
//                wxPayService.refund(order, "审核后退押金",remainingDeposit,outRefundNo);
//            }
//            return Boolean.TRUE;
//        });
//        if(!execute)throw new ServiceException("商家还车失败");
//        return true;
//    }

//    @NotNull
//    private String saveDepositRefundObj(OrderVO rlOrderVO, BigDecimal refundAmount) {
//        String outRefundNo = IdUtils.getOrderNo("ref");
//        Refund refund1= createRefund("押金退款", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, outRefundNo,ServiceConstants.REFUND_TYPE_DEPOSIT);
//        int refundResult = refundService.insertEtRefund(refund1);
//        if(refundResult>0){
//            logger.info("保存退款对象成功");
//        }
////        logger.info("总押金：【{}】，退款金额：【{}】", rlOrderVO.getDeposit(), refundAmount);
//        return outRefundNo;
//    }

    private void updateOrderStatus(String orderNo) {
        Order updateOrder = new Order();
        updateOrder.setOrderNo(orderNo);
//        updateOrder.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END);
        int i = orderMapper.updateRlOrderByOrderNo(updateOrder);
        if(i==0){
            logger.info("【商家还车】更新订单信息失败");
            throw new ServiceException("【商家还车】更新订单信息失败");
        }
    }

    /**
     * 退款
     * 1. 校验
     * 2. 用户余额不足判断
     * 3. 计算出退款的比例
     * 4. 遍历用户，新增账变
     * 5. 新增退款明细
     * 6. 发起退款
     */
    @Transactional
    @Override
    public int refund(OrderQuery etOrder) {
//        //根据订单号查询订单信息
//        /** 1. 校验 */
//        EOrderVO rlOrderVO = orderMapper.selectRlOrderByOrderNo(etOrder.getOrderNo());
//        refundVerify(rlOrderVO);
//        /** 2.计算出退款的比例 保留两位小数点  比如退款金额为5元，  订单金额为32元  退款比例 = 5/32 = 0.16 （四舍五入）由系统来平账*/
//        //退款金额  调度费(商家取车)  配送费（送车上门）  租赁费
////        BigDecimal refundAmount = new BigDecimal("0");
////        BigDecimal refundPercentage = refundAmount.divide(rlOrderVO.getPayFee(), 2, RoundingMode.HALF_UP);
////        BigDecimal finalRefundAmount = refundAmount;
//        Boolean execute = transactionTemplate.execute(e -> {
//            /** 3. 根据分成列表，遍历用户，新增账变 */
////            refundDividendHandle(rlOrderVO, refundPercentage);
//            /** 4.记录退款表  创建退款对象*/
//            String outRefundNo = saveRefundObj(rlOrderVO, finalRefundAmount, dispatchFee, deliveryFee, leaseFee);
//            if(!orderOperService.recordOrderHistory(rlOrderVO.getOrderNo(),ServiceConstants.ORDER_OPERATION_REFUND,
//                    rlOrderVO.getStatus(),rlOrderVO.getStatus(),rlOrderVO.getPayFee(),rlOrderVO.getPayFee(),rlOrderVO.getUserId(),rlOrderVO.getPhone(),"已退款: "+finalRefundAmount+"元")){
//                throw new ServiceException("【退款】更新订单信息失败");
//            }
//            /** 5. 发起退款 */
//            wxPayService.refund(rlOrderVO, "商家退款金额", finalRefundAmount,outRefundNo);
//            return Boolean.TRUE;
//        });
//        if(!execute)throw new ServiceException("【订单退款】失败");
        return 1;
    }

//    @NotNull
//    private String saveRefundObj(OrderVO rlOrderVO, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal deliveryFee, BigDecimal leaseFee) {
//        String outRefundNo = IdUtils.getOrderNo("ref");
//        Refund refund1= createRefund("商家退款金额", rlOrderVO.getUserId(), rlOrderVO.getOrderNo(), refundAmount, dispatchFee, deliveryFee, leaseFee, outRefundNo,ServiceConstants.REFUND_TYPE_SYSTEM);
//        int refundResult = refundService.insertEtRefund(refund1);
//        if(refundResult>0){
//            logger.info("保存退款对象成功");
//        }
//        logger.info("总金额：【{}】，退款金额：【{}】", rlOrderVO.getTotalFee(), refundAmount);
//        return outRefundNo;
//    }

//    private void refundDividendHandle(RlOrderVO rlOrderVO, BigDecimal refundPercentage) {
//        List<RlDividendDetailVO> dividendDetails = rlDividendDetailService.selectRlDividendDetailListByOrderNo(rlOrderVO.getOrderNo());
//        for(RlDividendDetail detail:dividendDetails){
//            /** 4.1 余额不足判断 */
////            RlUserExt rlUserExt = userExtService.selectRlUserExtByUserId(detail.getPartnerId());
//            EUser user = userService.selectUserById(rlUserExt.getUserId());
//            // 计算出这个用户将要退款的金额
//            BigDecimal userRefundAmount = detail.getDividendAmount().multiply(refundPercentage);//用户退款金额  = 0.16 * 5元 = 0.8元  如果这个值小于余额则提示 余额不足
//            BigDecimal subtract = user.getBalance().subtract(userRefundAmount);
//            if(subtract.compareTo(BigDecimal.ZERO) <= 0){
//                throw new ServiceException("用户【"+user.getPhonenumber()+"】余额不足，不能退款");
//            }
//            /** 4.2 新增账变 */
//            int i = changeBalanceService.generateChanggeBalance(rlOrderVO.getOrderNo(), rlOrderVO.getOutTradeNo(), ServiceConstants.FLOW_TYPE_DISBURSE,
//                    ServiceConstants.ORDER_REFUND, userRefundAmount, rlUserExt.getUserId(), user.getUserName(), user.getPhonenumber(),user.getUserType());
//            if(i<=0)throw new ServiceException("用户【"+user.getPhonenumber()+"】新增账变失败");
//            /** todo 4.3 更新分成表中的退款金额 */
//            int i1 = rlDividendDetailService.updateRefundAmount(detail.getId(), userRefundAmount);
//            if(i1<=0)throw new ServiceException("【退款】更新分成表中的退款金额失败");
//        }
//    }

    /** 退款校验*/
    private void refundVerify(OrderVO rlOrderVO) {
        if(ObjectUtil.isNull(rlOrderVO)){
            throw new ServiceException("订单不存在");
        }
//        if (!ServiceConstants.ORDER_STATUS_ORDER_END.equals(rlOrderVO.getStatus())) {
//            throw new ServiceException("退款失败，订单未结束");
//        }
        if(ORDER_PAY_STATUS_NON_PAYMENT.equals(rlOrderVO.getPaid())){
            throw new ServiceException("订单未支付，不能退款");
        }
    }

    @Override
    public Refund createRefund(String reason, Long userId, String orderNo, BigDecimal refundAmount, BigDecimal dispatchFee, BigDecimal deliveryFee, BigDecimal leaseFee, String outRefundNo, String type) {
        Refund etRefund = new Refund();
        etRefund.setAmount(refundAmount);
        etRefund.setReason(reason);
//        etRefund.setDispatchFee(dispatchFee);
//        etRefund.setDeliveryFee(deliveryFee);
//        etRefund.setLeaseFee(leaseFee);
//        etRefund.setOrderNo(orderNo);
        etRefund.setUserId(userId);
        etRefund.setRefundNo(outRefundNo);
//        etRefund.setType(type);
//        if(type.equals(ServiceConstants.REFUND_TYPE_DEPOSIT)){
//            etRefund.setItemDesc("押金退款");
//        }else{
//            StringBuilder itemDesc = new StringBuilder();
//            if(ObjectUtil.isNotNull(deliveryFee) && !deliveryFee.equals(BigDecimal.ZERO)){
//                itemDesc.append("配送费:").append(deliveryFee).append("元,");
//            }
//            if(ObjectUtil.isNotNull(dispatchFee) && !dispatchFee.equals(BigDecimal.ZERO)){
//                itemDesc.append("调度费:").append(dispatchFee).append("元,");
//            }
//            if(ObjectUtil.isNotNull(leaseFee) && !leaseFee.equals(BigDecimal.ZERO)){
//                itemDesc.append("租赁费:").append(leaseFee).append("元,");
//            }
//            etRefund.setItemDesc(itemDesc.toString());
//        }
        return etRefund;
    }

//
//    /**
//     * 计算价格
//     */
//    @Override
//    public PriceVO calculatePrice(EOrderQuery order) {
//        PriceVO priceVO = new PriceVO();
//        BigDecimal totalFee = BigDecimal.ZERO;
//        // 租金
//        BigDecimal rentFee = rentFee(order, priceVO);
//        totalFee = totalFee.add(rentFee);
//        priceVO.setTotalFee(totalFee);
//        return priceVO;
//    }

//    /**
//     * 根据订单号查询可还车的店铺
//     */
//    @Override
//    public List<StoreVo> getReturnStoreList(String orderNo,String lon,String lat) {
//        RlOrderVO order = orderMapper.selectRlOrderByOrderNo(orderNo);
//        List<StoreVo> storeVos = storeService.selectSmStoreListBYMerchantId(order.getMerchantId());
//        for (StoreVo storeVo:storeVos) {
//            BigDecimal storeLon = storeVo.getLng();
//            BigDecimal storeLat = storeVo.getLat();
//            if (storeLon != null && storeLat != null && StrUtil.isNotBlank(lon) && StrUtil.isNotBlank(lat)) {
//                double[] point1 = {storeLon.doubleValue(), storeLat.doubleValue()};
//                double[] point2 = {Double.valueOf(lon), Double.valueOf(lat)};
//                double distance = GeoUtils.haversineDistance(point1, point2);
//                BigDecimal distanceFormatted = new BigDecimal(distance).setScale(1, RoundingMode.HALF_UP);
//                storeVo.setDistance(distanceFormatted.doubleValue());
//            }
//        }
//        List<StoreVo> storeList = new ArrayList<>(storeVos);
//        Collections.sort(storeList, new Comparator<StoreVo>() {
//            @Override
//            public int compare(StoreVo o1, StoreVo o2) {
//                // 注意：由于我们想要按距离由近到远排序，因此当 o1 的距离小于 o2 的距离时，应返回 -1
//                // 当距离相等时返回 0，当 o1 的距离大于 o2 的距离时返回 1
//                return Double.compare(o1.getDistance(), o2.getDistance());
//            }
//        });
//        return storeList;
//    }
//
//    /**
//     * 根据sn查询正在进行中的订单
//     */
//    @Override
//    public OrderVO getInProgressOrder(String sn) {
//        List<OrderVO> orders = orderMapper.getInProgressOrder(sn);
//        if(ObjectUtil.isNotNull(orders.size()) && !orders.isEmpty()){
//            return orders.get(0);
//        }
//        return null;
//    }

    @Override
    public void validate(OrderQuery orderQuery) {
        if(StrUtil.isBlank(orderQuery.getOrderNo())){
            throw new ServiceException("订单号不能为空");
        }
        if(StrUtil.isBlank(orderQuery.getType())){
            throw new ServiceException("类型不能为空");
        }
        if(orderQuery.getRuleId() == null || orderQuery.getRuleId() <= 0){
            throw new ServiceException("套餐id不能为空");
        }
    }

    /**
     * 首页统计
     */
    @Override
    public IndexAdminVo indexStatistics() {
        return getIndexAdminVoByAgentId();
    }

    /**
     * 已售数量
     */
    @Override
    public int selectSoldNum(Long roomId) {
        return orderMapper.selectSoldNum(roomId);
    }

    /**
     * 已预约订单时间段
     */
    @Override
    public List<ReservedTimePeriod> selectReservedTimes(Long roomId, Date startTime, Date endTime) {
        return orderMapper.selectReservedTimes(roomId, startTime, endTime);
    }

    /**
     * 更换包间
     */
    @Override
    public int changeRoom(OrderQuery order) {
        return orderMapper.changeRoom(order);
    }


    @NotNull
    private IndexAdminVo getIndexAdminVoByAgentId() {
        Long merchantId = getUserId();
        IndexAdminVo indexAdminVo = new IndexAdminVo();

        /** 收入统计 */
        setIncome(merchantId,indexAdminVo);

        /** 当前营运情况 */
        setDeviceOverview(merchantId,indexAdminVo);

        // 设置车辆统计数据
        return indexAdminVo;
    }


    @Override
    public IndexIncomeList getIndexInComeList(String timeLimit) {
        /** 运营概况 */
        Long merchantId = getUserId();
        IndexIncomeList indexAdminVo = new IndexIncomeList();
        List<InCome> incomeVos;
        if(TIME_LIMIT_30_DAYS.equals(timeLimit)){
            incomeVos = dividendDetailService.select30DaysIncome(merchantId);
        }else{
            // 查询7天的数据
            incomeVos = dividendDetailService.select7DaysIncome(merchantId);
        }
        indexAdminVo.setIncomeVoList(incomeVos);
        // 根据查询出来的incomeVos，合计订单金额和订单数,保存到 indexAdminVo中
        indexAdminVo.setTotalIncome(incomeVos.stream().map(InCome::getOrderIncome).reduce(BigDecimal.ZERO, BigDecimal::add));
        indexAdminVo.setTotalOrderNum(incomeVos.stream().map(InCome::getOrderNum).reduce(0, Integer::sum));
        return indexAdminVo;
    }


    @Override
    public AdminIndexDataVO adminIndexStatistics() {
        AdminIndexDataVO adminIndexDataVO = new AdminIndexDataVO();

        // 用户余额
        BigDecimal userBalance = userService.selectAllBalance();
        adminIndexDataVO.setUserBalance(userBalance);

        // 今日余额
        UserBalanceQuery userBalanceQuery = new UserBalanceQuery();
        BigDecimal todayUserBalance = userBalanceService.selectUserBalance(userBalanceQuery);
        adminIndexDataVO.setTodayBalance(todayUserBalance);

        // 商户数
        Integer merchantCount = userService.selectCount(new UserQuery());
        adminIndexDataVO.setMerchantCount(merchantCount);

        // 店铺数
        Integer storeCount = storeService.selectCount(null);
        adminIndexDataVO.setStoreCount(storeCount);

        // 订单金额
        BigDecimal orderAmount = orderMapper.getOrderFee(new OrderQuery());
        adminIndexDataVO.setOrderAmount(orderAmount);

        // 订单数
        Integer orderCount = orderMapper.getOrderNum(null, null, null);
        adminIndexDataVO.setOrderCount(orderCount);

        // 总设备数
        DeviceQuery deviceQuery = new DeviceQuery();
        int totalDeviceCount = deviceService.selectCount(deviceQuery);
        adminIndexDataVO.setTotalDeviceCount(totalDeviceCount);

        // 已投放设备数（使用中设备数）
        deviceQuery.setPlacementStatus(DEVICE_PLACEMENT_STATUS_PLACED);
        int activeDeviceCount = deviceService.selectCount(deviceQuery);
        adminIndexDataVO.setActiveDeviceCount(activeDeviceCount);

        // 房间数
        RoomQuery query = new RoomQuery();
        query.setType2(ROOM_TYPE2_PRIVATE_ROOM);
        int roomCount = roomService.getCount(query);
        adminIndexDataVO.setRoomCount(roomCount);

        // 大厅设施数
        query.setType2(ROOM_TYPE2_LOBBY_DEVICE);
        int hallFacilityCount = roomService.getCount(query);
        adminIndexDataVO.setHallFacilityCount(hallFacilityCount);

        // 使用中大厅设施数
        query.setStatus(ROOM_STATUS_INUSE);
        int activeHallFacilityCount = roomService.getCount(query);
        adminIndexDataVO.setActiveHallFacilityCount(activeHallFacilityCount);

        // 使用中房间数
        query.setType2(ROOM_TYPE2_PRIVATE_ROOM);
        int activeRoomCount = roomService.getCount(query);
        adminIndexDataVO.setActiveRoomCount(activeRoomCount);

        // 合作意向数
        int partnershipIntentCount = intentionService.selectCount(new IntentionQuery());
        adminIndexDataVO.setPartnershipIntentCount(partnershipIntentCount);

        // 提现申请数
        WithdrawQuery withdraw = new WithdrawQuery();
        withdraw.setStatus(WITHDRAW_STATUS_APPLY);
        int withdrawalRequestCount = withdrawService.selectCount(withdraw);
        adminIndexDataVO.setWithdrawalRequestCount(withdrawalRequestCount);

        return adminIndexDataVO;
    }

    /**
     * 后台首页图表数据
     */
    @Override
    public IndexChartDatas adminIndexChartData(IndexChartQuery query) {
        IndexChartDatas indexChartDatas = new IndexChartDatas();
        // 获取开始时间和结束时间
        LocalDate startDate = query.getStartTime();
        LocalDate endDate = query.getEndTime();

        List<OrderInCome> inComes = new ArrayList<>();  // 初始化 inComes 列表
        List<PlatformInCome> platformInComes = new ArrayList<>();
        List<RechargeWithdrawal> rechargeWithdrawals = new ArrayList<>();
        List<UserBalanceData> userBalances = new ArrayList<>();

        // 在遍历日期范围时，直接修改 query 对象的 startTime 和 endTime 属性
        while (!startDate.isAfter(endDate)) {
            // 执行查询
            ReconciliationQuery reconcile =  new ReconciliationQuery();
            reconcile.setStartTime(startDate);
            reconcile.setEndTime(startDate);  // 设置当天的最后一刻
            List<ReconciliationVO> reconciliationVOS = reconciliationService.selectReconciliationListGroupBy(reconcile);

            for (ReconciliationVO vo : reconciliationVOS) {
                //订单统计
                OrderInCome orderInCome = new OrderInCome();
                orderInCome.setDay(startDate);
                orderInCome.setOrderPaid(vo.getOrderPaid());
                orderInCome.setOrderRefund(vo.getOrderRefund());
                orderInCome.setSettlementAmount(vo.getSettlementAmount());
                orderInCome.setUserDivide(vo.getUserDivide());
                inComes.add(orderInCome);  // 将新的 OrderInCome 对象添加到列表中

                //平台统计
                PlatformInCome platformInCome = new PlatformInCome();
                platformInCome.setDay(startDate);
                platformInCome.setPlatformServiceFee(vo.getPlatformServiceFee());
                platformInCome.setWithdrawServiceFee(vo.getWithdrawServiceFee());
                platformInCome.setChannelCost(vo.getChannelCost());
                platformInCome.setPlatformRevenue(vo.getPlatformRevenue());
                platformInComes.add(platformInCome);  // 添加到 incomeAndCost 列表

                // 充值统计
                RechargeWithdrawal rechargeWithdrawal = new RechargeWithdrawal();
                rechargeWithdrawal.setDay(startDate);
                rechargeWithdrawal.setWithdrawAmount(vo.getUserWithdrawAmount());
                rechargeWithdrawals.add(rechargeWithdrawal);  // 添加到 incomeAndCost 列表

                // 用户余额统计
                UserBalanceData userBalance = new UserBalanceData();
                userBalance.setDay(startDate);
                userBalance.setUserBalance(vo.getUserBalance());
                userBalances.add(userBalance);
            }

            // 下一天
            startDate = startDate.plusDays(1);
        }
        // 设置对账图表的数据
        indexChartDatas.setReconciliation(inComes);
        indexChartDatas.setIncomeAndCost(platformInComes);
        indexChartDatas.setRechargeWithdrawal(rechargeWithdrawals);
        indexChartDatas.setUserBalance(userBalances);
        return indexChartDatas;
    }


    private void setDeviceOverview(Long merchantId, IndexAdminVo indexAdminVo) {
        RoomQuery query = new RoomQuery();
        query.setMerchantId(merchantId);
        query.setType2(ROOM_TYPE2_PRIVATE_ROOM);
        query.setStatus(ROOM_STATUS_INUSE);
        indexAdminVo.setInUseRoomNum(roomService.getCount(query));
        query.setStatus(null);
        indexAdminVo.setTotalRoomNum(roomService.getCount(query));

        query.setType2(ROOM_TYPE2_LOBBY_DEVICE);
        indexAdminVo.setTotalEquNum(roomService.getCount(query));
        query.setStatus(ROOM_STATUS_INUSE);
        indexAdminVo.setInUseEquNum(roomService.getCount(query));

        DeviceQuery deviceQuery = new DeviceQuery();
        deviceQuery.setUserId(merchantId);
        indexAdminVo.setTotalDeviceNum(deviceService.selectCount(deviceQuery));

        deviceQuery.setStatus(DeviceStatus.USING.getStatus());
        indexAdminVo.setInUseDeviceNum(deviceService.selectCount(deviceQuery));

    }

    private void setIncome(Long merchantId, IndexAdminVo indexAdminVo) {
        // 获取今日收入和订单数
        indexAdminVo.setTodayIncome(getIncomeByTimeType(merchantId, TIME_LIMIT_TODAY));
        indexAdminVo.setTodayOrderNum(getOrderCountByTimeType(merchantId, TIME_LIMIT_TODAY));

        DividendDetailQuery dividendDetailQuery = new DividendDetailQuery();
        dividendDetailQuery.setStatus(DIVIDEND_STATUS_PAID);
        dividendDetailQuery.setPartnerId(merchantId);
        indexAdminVo.setTotalIncome(dividendDetailService.getIncome(dividendDetailQuery));
        indexAdminVo.setTotalOrderNum(orderMapper.getOrderNum(merchantId, null, null));
        UserVO userVO = userService.selectUserById(merchantId);
        ServiceUtil.assertion(userVO == null, "商户不存在");
        indexAdminVo.setBalance(userVO.getBalance());
    }

    // 根据时间差收入
    public BigDecimal getIncomeByTimeType(Long merchantId, String timeType) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime;

        switch (timeType) {
            case TIME_LIMIT_TODAY:
                // 今日收入
                startTime = now.with(LocalTime.MIN);
                break;
            case TIME_LIMIT_WEEK:
                // 本周收入（周一到现在）
                startTime = now.with(LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                break;
            case TIME_LIMIT_MONTH:
                // 本月收入
                startTime = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
                break;
            default:
                throw new IllegalArgumentException("时间类型无效");
        }

        DividendDetailQuery dividendDetailQuery = new DividendDetailQuery();
        dividendDetailQuery.setStatus(DIVIDEND_STATUS_PAID);
        dividendDetailQuery.setPartnerId(merchantId);
        dividendDetailQuery.setStartTime(startTime.toLocalDate());
        dividendDetailQuery.setEndTime(now.toLocalDate());
        return dividendDetailService.getIncome(dividendDetailQuery);
    }

    // 根据时间和店铺id查收入
    public BigDecimal getRevenueByTimeType(String timeType,OrderQuery query) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime;

        switch (timeType) {
            case TIME_LIMIT_TODAY:
                // 今日收入
                startTime = now.with(LocalTime.MIN);
                break;
            case TIME_LIMIT_WEEK:
                // 本周收入（周一到现在）
                startTime = now.with(LocalTime.MIN).with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                break;
            case TIME_LIMIT_MONTH:
                // 本月收入
                startTime = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
                break;
            default:
                throw new IllegalArgumentException("时间类型无效");
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        query.setStartTime(startTime.format(formatter));
        query.setEndTime(now.format(formatter));
        return orderMapper.getOrderFee(query);
    }

    public Integer getOrderCountByTimeType(Long merchantId, String timeType) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime;

        switch (timeType) {
            case TIME_LIMIT_TODAY:
                // 今日订单数
                startTime = now.with(LocalTime.MIN);
                break;
            case TIME_LIMIT_WEEK:
                // 本周订单数
                startTime = now.with(LocalTime.MIN)
                        .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                break;
            case TIME_LIMIT_MONTH:
                // 本月订单数
                startTime = now.with(TemporalAdjusters.firstDayOfMonth())
                        .with(LocalTime.MIN);
                break;
            default:
                throw new IllegalArgumentException("时间类型无效");
        }

        return orderMapper.getOrderNum(merchantId, startTime, now);
    }

    /**
     * 进行中的订单
     */
    @Override
    public List<OrderVO> getInProgressOrderList(Long roomId) {
        return orderMapper.getInProgressOrderList(roomId);
    }

    /**
     * 根据userId查询进行中的订单
     */
    @Override
    public List<OrderVO> getInProgressOrderListByUserId(Long userId) {
        List<OrderVO> inProgressOrderListByUserId = orderMapper.getInProgressOrderListByUserId(userId);
        updateGateOnlineStatus(inProgressOrderListByUserId);
        return inProgressOrderListByUserId;
    }

    /**
     * 更新订单列表中每个订单的网关在线状态。
     * @param orders 订单列表
     */
    private void updateGateOnlineStatus(List<OrderVO> orders) {
        if (orders == null || orders.isEmpty()) {
            return;
        }

        for (OrderVO order : orders) {
            updateGateOnlineStatus(order);
        }
    }

    private void updateGateOnlineStatus(OrderVO order) {
        if (order == null) {
            return;
        }
        Long gateId = order.getGateId();
        if (gateId != null) {
            DeviceVO deviceVO = deviceService.selectById(gateId);
            if (deviceVO != null) {
                order.setGateOnlineStatus(deviceVO.getOnlineStatus());
            }
        }
    }


    /**
     * 根据用户id查询历史订单
     */
    @Override
    public List<OrderVO> getHistoricalOrderListByUserId(Long userId){
        return orderMapper.getHistoricalOrderListByUserId(userId);
    }
    /**
     * 获取已结束订单
     */
    @Override
    public List<OrderVO> selectEndOrderList() {
        return orderMapper.selectEndOrderList();
    }

    /**
     * 获取待使用订单
     */
    @Override
    public List<OrderVO> selectToeUsedOrderList() {
        return orderMapper.selectToeUsedOrderList();
    }

    /**
     * 查询押金模式还未退金额的订单
     */
    public List<OrderVO> selectNotRefundedOrderList() {
        return orderMapper.selectNotRefundedOrderList();
    }

    /**
     * 数量统计
     */
    @Override
    public Integer getCount(OrderQuery order) {
        return orderMapper.getCount(order);
    }

    /**
     * 统计营收
     */
    @Override
    public BigDecimal getOrderFee(OrderQuery order) {
        return orderMapper.getOrderFee(order);
    }

    /**
     * 平台服务费
     */
    @Override
    public BigDecimal getPlatformServiceFee(OrderQuery query) {
        return orderMapper.getPlatformServiceFee(query);
    }

    /**
     * 统计营收（根据日期返回）
     */
    public List<InCome> getInComeList(OrderQuery rlOrder){
        return orderMapper.getInComeList(rlOrder);
    }

    /**
     * 增加订单中的退款金额
     */
    @Override
    public int addRefundAmountByOrderNo(String orderNo, BigDecimal refundAmount) {
        return orderMapper.addRefundAmountByOrderNo(orderNo,refundAmount);
    }

}
