package shop.alien.job.store;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import shop.alien.entity.store.*;
import shop.alien.entity.store.vo.LifeUserOrderVo;
import shop.alien.job.feign.AlienStoreFeign;
import shop.alien.mapper.*;
import shop.alien.util.common.UniqueRandomNumGenerator;
import shop.alien.util.common.constant.CouponTypeEnum;
import shop.alien.util.common.constant.DiscountCouponEnum;
import shop.alien.util.common.constant.OrderStatusEnum;
import shop.alien.util.common.constant.PaymentEnum;
import shop.alien.util.type.LifeNoticeUtil;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户订单任务
 * 待支付订单超时处理
 *
 * @author lyx
 * @date 2023/12/20 14:20
 * @see shop.alien.entity.store.LifeUserOrder
 */

@Slf4j
@Component
@RequiredArgsConstructor
public class LifeUserOrderJob {

    private final LifeUserOrderMapper lifeUserOrderMapper;
    private final OrderCouponMiddleMapper orderCouponMiddleMapper;
    private final LifeCouponMapper lifeCouponMapper;
    private final LifeGroupBuyMainMapper lifeGroupBuyMainMapper;
    private final AlienStoreFeign alienStoreFeign;
    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
    private final LifeRefundOrderMapper lifeRefundOrderMapper;
    private final LifeUserMapper lifeUserMapper;
    private final LifeNoticeMapper lifeNoticeMapper;

    private final LifeNoticeUtil lifeNoticeUtil;

    /**
     * 待支付订单超时处理
     */
    @XxlJob("autoCancelUnpaidOrders")
    @Transactional(rollbackFor = Exception.class)
    public String autoCancelUnpaidOrders() {
        //1.查询待支付超时订单
        List<LifeUserOrder> lifeUserOrders = lifeUserOrderMapper.selectList(new LambdaQueryWrapper<LifeUserOrder>()
                .eq(LifeUserOrder::getStatus, OrderStatusEnum.WAIT_PAY.getStatus())
                .le(LifeUserOrder::getBuyTime, LocalDateTime.now().minusMinutes(30)));
        if (CollectionUtils.isEmpty(lifeUserOrders)) {
            return "无待支付超时订单";
        }
        //2.超时则取消订单id
        List<String> orderIds = lifeUserOrders.stream().map(LifeUserOrder::getId).collect(Collectors.toList());
        lifeUserOrderMapper.update(null, new LambdaUpdateWrapper<LifeUserOrder>()
                .set(LifeUserOrder::getStatus, OrderStatusEnum.CANCEL.getStatus())
                .set(LifeUserOrder::getCancelTime, LocalDateTime.now())
                .set(LifeUserOrder::getCancelReason, "订单超时未支付")
                .set(LifeUserOrder::getFinishTime, LocalDateTime.now())
                .in(LifeUserOrder::getId, orderIds));
        // 根据类型分组
        Map<Integer, List<String>> collect = lifeUserOrders.stream().filter(order -> order.getCouponType() != null)
                .collect(Collectors.groupingBy(
                        LifeUserOrder::getCouponType,  // 按订单类型分组
                        Collectors.mapping(  // 对每个分组中的元素提取ID
                                LifeUserOrder::getId,
                                Collectors.toList()
                        )
                ));
        int updateNum = 0;
        if (collect.containsKey(1)) {
            //3.1代金券订单
            List<String> couponOrderIds = collect.get(1);
            QueryWrapper<OrderCouponMiddle> queryWrapper = new QueryWrapper<OrderCouponMiddle>().in("order_id", couponOrderIds)
                    .eq("status", OrderStatusEnum.WAIT_PAY.getStatus())
                    .groupBy("coupon_id")  // 按coupon_id分组
                    .select("coupon_id, COUNT(*) as count");  // 选择分组字段和统计数量
            List<OrderCouponMiddle> orderCouponMiddles = orderCouponMiddleMapper.selectList(queryWrapper);
            for (OrderCouponMiddle orderCouponMiddle : orderCouponMiddles) {
                // 恢复库存
                lifeCouponMapper.update(null, new LambdaUpdateWrapper<LifeCoupon>()
                        .setSql("single_qty=single_qty+" + orderCouponMiddle.getCount())
                        .eq(LifeCoupon::getId, orderCouponMiddle.getCouponId()));
            }
        }
        if (collect.containsKey(2)) {
            //3.2团购订单
            List<String> groupOrderIds = collect.get(2);
            QueryWrapper<OrderCouponMiddle> queryWrapper = new QueryWrapper<OrderCouponMiddle>().in("order_id", groupOrderIds)
                    .eq("status", OrderStatusEnum.WAIT_PAY.getStatus())
                    .groupBy("coupon_id")  // 按coupon_id分组
                    .select("coupon_id, COUNT(*) as count");
            List<OrderCouponMiddle> orderCouponMiddles = orderCouponMiddleMapper.selectList(queryWrapper);
            for (OrderCouponMiddle orderCouponMiddle : orderCouponMiddles) {
                // 恢复库存
                lifeGroupBuyMainMapper.update(null, new LambdaUpdateWrapper<LifeGroupBuyMain>()
                        .setSql("inventory_num=inventory_num+" + orderCouponMiddle.getCount())
                        .eq(LifeGroupBuyMain::getId, orderCouponMiddle.getCouponId()));
            }
        }
        // 更新券状态
        orderCouponMiddleMapper.update(null, new LambdaUpdateWrapper<OrderCouponMiddle>()
                .set(OrderCouponMiddle::getStatus, OrderStatusEnum.CANCEL.getStatus())
                .in(OrderCouponMiddle::getOrderId, orderIds));
        return "success";
    }

    /**
     * 自动更新总订单状态
     */
    @XxlJob("autoUpdateOrderStatus")
    @Transactional(rollbackFor = Exception.class)
    public String autoUpdateOrderStatus() {
        // 定义需要排除的订单状态集合
        Set<Integer> excludeStatuses = new HashSet<>(Arrays.asList(
                OrderStatusEnum.CANCEL.getStatus(),
                OrderStatusEnum.WAIT_PAY.getStatus(),
                OrderStatusEnum.WAIT_USE.getStatus(),
                OrderStatusEnum.REFUND_FAILED.getStatus()
        ));
        // 查询所以已完成的订单id
        List<OrderCouponMiddle> orderCouponMiddles = orderCouponMiddleMapper.selectList(
                new LambdaQueryWrapper<OrderCouponMiddle>()
                        .select(OrderCouponMiddle::getOrderId)
                        .eq(OrderCouponMiddle::getDeleteFlag, 0)
                        .in(OrderCouponMiddle::getStatus, excludeStatuses)
                        .groupBy(OrderCouponMiddle::getOrderId)
        );
        // 批量更新为已完成
        lifeUserOrderMapper.update(null, new UpdateWrapper<LifeUserOrder>()
                .set("status", OrderStatusEnum.COMPLETE.getStatus())
                .notIn("id", orderCouponMiddles.stream().map(OrderCouponMiddle::getOrderId).collect(Collectors.toList())));
        return "success";
    }


    /**
     * 过期自动退
     */
    @XxlJob("expiredRefundTask")
    @Transactional(rollbackFor = Exception.class)
    public void expiredRefundTask() {
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        now = calendar.getTime();
        QueryWrapper<LifeUserOrder> selectWrapper = new QueryWrapper<>();
        // 查询状态为待使用的
        List<Integer> status = new ArrayList<>();
        status.add(OrderStatusEnum.WAIT_USE.getStatus());
        selectWrapper.inSql("luo.id", "SELECT distinct order_id FROM order_coupon_middle WHERE status in ( "+String.join(",", status.stream().map(String::valueOf).collect(Collectors.toList()))+")");
        // 查询待使用的订单
        List<LifeUserOrderVo> orderList = lifeUserOrderMapper.selectRefundList(selectWrapper);

        if (!orderList.isEmpty()) {
            for (LifeUserOrderVo order : orderList) {
                Date payTime = order.getPayTime();
                // 根据有效期类型不同 进行不同判断 1: 指定天数，2：指定时间段
                String effectiveDateValue = order.getEffectiveDateValue();
                calendar.setTime(payTime);
                Date guoqiDate = null;
                if ("0".equals(order.getEffectiveDateType())) {
                    // 固定天数则加
                    calendar.add(Calendar.DAY_OF_MONTH, Integer.valueOf(effectiveDateValue));
                    guoqiDate = calendar.getTime();
                } else {
                    // 指定时间段
                    String goqiDate = null;
                    if(order.getCouponType() == CouponTypeEnum.COUPON.getCode()){
                        // 1. 将字符串转换为 long 类型
                        long timestamp = Long.parseLong(effectiveDateValue.split(",")[1]);
                        // 2. 使用 timestamp 构建 Date 对象
                        Date date = new Date(timestamp);
                        // 如果你需要特定格式的字符串，可以再进行格式化
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                        goqiDate =sdf.format(date);
                    } else {
                        goqiDate = effectiveDateValue.split(",")[1];
                    }
                    try {
                        guoqiDate = new SimpleDateFormat("yyyy-MM-dd").parse(goqiDate);
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                }
                Date endDate = order.getEndDate();
                if (now.compareTo(guoqiDate) > 0 || now.compareTo(endDate) > 0) {
                    // 过滤出退款的券列表
                    List<OrderCouponMiddle> orderCouponMiddleList = order.getOrderCouponMiddleList();
                    List<OrderCouponMiddle> refundList = orderCouponMiddleList.stream().filter(x -> x.getStatus() == OrderStatusEnum.WAIT_USE.getStatus() || x.getStatus() == OrderStatusEnum.REFUND_FAILED.getStatus()).collect(Collectors.toList());
                    List<OrderCouponMiddle> refundedList = orderCouponMiddleList.stream().filter(x -> x.getStatus() == OrderStatusEnum.REFUND.getStatus()).collect(Collectors.toList());
                    List<Integer> collect = refundList.stream().map(x -> x.getId()).collect(Collectors.toList());
                    if (!refundList.isEmpty()) {
                        // 调用退款接口
                        // 统计退款金额
                        BigDecimal totalRefundAmount = refundList.stream().map(x -> x.getPrice()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        // 判断本次是否是全退 执行退款
                        String refundResult = "";
                        String partialRefundCode = "";
                        if (refundList.size() != orderCouponMiddleList.size()) {
                            partialRefundCode = UniqueRandomNumGenerator.generateUniqueCode(12);
                        }
                        String payMethod = order.getPayMethod();
                        String payType = "";
                        Map<String, String> params = new HashMap<>();
                        if("支付宝支付".equals(payMethod)) {
                            payType = PaymentEnum.ALIPAY.getType();
                            params.put("payType", payType);
                            params.put("outTradeNo", order.getOrderNo());
                            params.put("refundAmount", totalRefundAmount.toString());
                            params.put("refundReason", "过期自动退");
                            params.put("partialRefundCode",partialRefundCode);
                        } else {
                            payType = PaymentEnum.WECHAT_PAY.getType();
                            params.put("payType", payType);
                            params.put("outTradeNo", order.getOrderNo());
                            params.put("reason", "过期自动退");
                            params.put("refundAmount", String.valueOf(totalRefundAmount.multiply(new BigDecimal(100)).longValue()));
                            params.put("totalAmount", String.valueOf(new BigDecimal(order.getFinalPrice()).multiply(new BigDecimal(100)).longValue()));
                        }
                        // 调用支付策略
                        try {
                            refundResult = alienStoreFeign.refunds(params).getData().toString();
                        } catch (Exception e) {
                            log.error(String.format("LifeUserOrderJob requestRefund error, payType: %s, params: %s, error: %s", payType, params, e.getMessage()));
                        }


                        if ("调用成功".equals(refundResult)) {
                            //  1.更新中间表状态
                            int updateNum = orderCouponMiddleMapper.update(null, new LambdaUpdateWrapper<OrderCouponMiddle>()
                                    .set(OrderCouponMiddle::getStatus, OrderStatusEnum.REFUND.getStatus())
                                    .in(OrderCouponMiddle::getId, collect));
                            if (updateNum != collect.size()) {
                                log.error("expiredRefundTask更新中间表状态失败");
                                throw new RuntimeException("expiredRefundTask更新中间表状态失败");
                            }
                            // 2.过期后更新库存
                            if (1 == order.getCouponType()) {
                                // 代金券
                                // 恢复库存
                                lifeCouponMapper.update(null, new LambdaUpdateWrapper<LifeCoupon>()
                                        .setSql("single_qty=single_qty+" + updateNum)
                                        .eq(LifeCoupon::getId, order.getCouponId()));
                            } else {
                                // 团购
                                lifeGroupBuyMainMapper.update(null, new LambdaUpdateWrapper<LifeGroupBuyMain>()
                                        .setSql("inventory_num=inventory_num+" + updateNum)
                                        .eq(LifeGroupBuyMain::getId, order.getCouponId()));
                            }
                            // 3.更新订单状态 退款+已退 = 全部券则更新总订单状态
                            if (refundList.size() + refundedList.size() == orderCouponMiddleList.size()) {
                                lifeUserOrderMapper.update(null, new LambdaUpdateWrapper<LifeUserOrder>()
                                        .set(LifeUserOrder::getStatus, OrderStatusEnum.REFUND.getStatus())
                                        .eq(LifeUserOrder::getId, order.getId()));
                                if (null != order.getQuanId()) {
                                    // 更新优惠券状态
                                    lifeDiscountCouponUserMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCouponUser>()
                                            .set(LifeDiscountCouponUser::getStatus, DiscountCouponEnum.WAITING_USED.getValue())
                                            .eq(LifeDiscountCouponUser::getId, order.getQuanId()));
                                }
                            }else {
                                // 累计退券个数+当前退券个数!=总个数 且 当前退券数量 = 可退券数
                                lifeUserOrderMapper.update(null,new UpdateWrapper<LifeUserOrder>().eq("id",order.getId())
                                        .set("status",OrderStatusEnum.COMPLETE.getStatus())
                                        .set("finish_time",now));
                            }
                            // 4.添加退款记录
                            LifeRefundOrder refundOrder = new LifeRefundOrder()
                                    .setOrderId(order.getId())
                                    .setUserId(order.getUserId())
                                    .setOrderId(order.getId())
                                    .setRefundCouponAmount(updateNum)
                                    .setReason("过期自动退")
                                    .setApplicationTime(now)
                                    .setRefundTime(now)
                                    .setStatus(0)
                                    .setRefundMoney(totalRefundAmount.toString());
                            if (lifeRefundOrderMapper.insert(refundOrder) > 0) {
                                // TODO 是否发送通知
                                // 发送通知
                                LifeNotice lifeMessage = new LifeNotice();
                                LifeUser lifeUser = lifeUserMapper.selectById(order.getUserId());
                                lifeMessage.setReceiverId("user_" + lifeUser.getUserPhone());
                                String text = "您的编号为" + order.getOrderNo() + "的订单过期自动退款，退款金额为" + totalRefundAmount.toString() + "元";
                                lifeMessage.setContext(text);
                                lifeMessage.setSenderId("system");
                                lifeMessage.setIsRead(0);
                                lifeMessage.setNoticeType(2);
                                lifeNoticeUtil.fillUserTypeAndRefId(lifeMessage);
                                lifeNoticeMapper.insert(lifeMessage);
                            }
                        }
                    } else {
                        // 更新中间表状态
                        //  1.更新中间表状态
//                        int updateNum = orderCouponMiddleMapper.update(null, new LambdaUpdateWrapper<OrderCouponMiddle>()
//                                .set(OrderCouponMiddle::getStatus, OrderStatusEnum.REFUND_FAILED.getStatus())
//                                .in(OrderCouponMiddle::getId, collect));
                        log.error("自动退款失败");
                        throw new RuntimeException("自动退款失败");
                    }
                }
            }
        }
    }
}

