package com.xinelu.quartz.service.impl;

import com.xinelu.applet.service.goodstock.GoodsStockService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatRefundService;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatRefundInfoVO;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.enums.*;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
import com.xinelu.manage.mapper.refundinfo.RefundInfoMapper;
import com.xinelu.manage.mapper.trainingorder.TrainingOrderMapper;
import com.xinelu.manage.vo.RefundOrderInfoVO;
import com.xinelu.manage.vo.TrainingRefundOrderVO;
import com.xinelu.quartz.service.RefundInfoTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @Description 微信退款定时任务业务层实现类
 * @Author 纪寒
 * @Date 2022-10-25 14:32:40
 * @Version 1.0
 */
@Slf4j
@Service
public class RefundInfoTaskServiceImpl implements RefundInfoTaskService {

    @Resource
    private AppointmentOrderMapper appointmentOrderMapper;
    @Resource
    private GoodsOrderMapper goodsOrderMapper;
    @Resource(name = "transactionManager")
    private DataSourceTransactionManager transactionManager;
    @Resource
    private WeChatRefundService weChatRefundService;
    @Resource
    private RefundInfoMapper refundInfoMapper;
    @Resource
    private GoodsStockService goodsStockService;
    @Resource
    private RedisTemplate<String, Objects> redisTemplate;
    @Resource
    private PatientCouponReceiveMapper patientCouponReceiveMapper;
    @Resource
    private TrainingOrderMapper trainingOrderMapper;

    /**
     * 自动处理退款状态定时任务，每15分钟执行一次
     * 防止由于网络等其它原因未接受到退款回调通知进而导致的退款单状态修改不及时
     */
    @Override
    public void automaticProcessRefundInfo() {
        List<RefundOrderInfoVO> appointmentOrderList = appointmentOrderMapper.getRefundAppointmentOrderInfo(OrderStatusEnum.WAIT_REFUND.getInfo(), RefundStatusEnum.PROCESSING.getInfo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
        List<RefundOrderInfoVO> refundGoodsOrderLit = goodsOrderMapper.getRefundGoodsOrderInfo(GooodsOrderStatusEnum.WAIT_REFUND.getInfo(), RefundStatusEnum.PROCESSING.getInfo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
        List<TrainingRefundOrderVO> trainingRefundOrderList = trainingOrderMapper.getTrainingRefundOrderList(TrainingOrderStatusEnum.PAY.getInfo(), RefundStatusEnum.PROCESSING.getInfo());
        if (CollectionUtils.isEmpty(appointmentOrderList) && CollectionUtils.isEmpty(refundGoodsOrderLit) && CollectionUtils.isEmpty(trainingRefundOrderList)) {
            return;
        }
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        List<RefundOrderInfoVO> successAppointOrderList = Lists.newArrayList();
        try {
            if (CollectionUtils.isNotEmpty(appointmentOrderList)) {
                successAppointOrderList = processAppointmentRefundInfo(appointmentOrderList);
            }
            if (CollectionUtils.isNotEmpty(refundGoodsOrderLit)) {
                processGoodsRefundInfo(refundGoodsOrderLit);
            }
            if (CollectionUtils.isNotEmpty(trainingRefundOrderList)) {
                handleRefundTrainingOrderInfo(trainingRefundOrderList);
            }
            transactionManager.commit(transactionStatus);
        } catch (Exception e) {
            transactionManager.rollback(transactionStatus);
            log.error("处理微信退款定时任务异常，异常信息 =====> {}", e.getMessage());
            if (CollectionUtils.isNotEmpty(successAppointOrderList)) {
                for (RefundOrderInfoVO refundOrderInfoVO : successAppointOrderList) {
                    String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + refundOrderInfoVO.getNurseStationItemId() + "_" + refundOrderInfoVO.getServiceDate() + "_" + refundOrderInfoVO.getServiceStartTime();
                    RedisAtomicLong redisAtomicLong = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
                    if (redisAtomicLong.get() > 0) {
                        redisAtomicLong.decrementAndGet();
                    }
                }
            }
            throw e;
        }
    }

    /**
     * 自动处理专家咨询订单医生手动拒单定时任务
     */
    @Override
    public void automaticProcessHealthConsultationRefund() {
        List<RefundOrderInfoVO> refundGoodsOrderLit = goodsOrderMapper.getRefundGoodsOrderInfo(GooodsOrderStatusEnum.REFUNDED.getInfo(), RefundStatusEnum.PROCESSING.getInfo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
        if (CollectionUtils.isEmpty(refundGoodsOrderLit)) {
            return;
        }
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            processHealthConsultationRefund(refundGoodsOrderLit);
            transactionManager.commit(transactionStatus);
        } catch (Exception e) {
            transactionManager.rollback(transactionStatus);
            log.error("处理专家咨询订单医生手动拒单定时任务异常，异常信息 =====> {}", e.getMessage());
            throw e;
        }
    }

    /**
     * 处理退款的预约订单信息
     *
     * @param appointmentOrderList 预约订单列表信息
     * @return 处理成功的订单编号集合
     */
    private List<RefundOrderInfoVO> processAppointmentRefundInfo(List<RefundOrderInfoVO> appointmentOrderList) {
        List<RefundOrderInfoVO> successList = Lists.newArrayList();
        for (RefundOrderInfoVO refundOrderInfoVO : appointmentOrderList) {
            if (StringUtils.isBlank(refundOrderInfoVO.getOrderNo()) || StringUtils.isBlank(refundOrderInfoVO.getOutRefundNo())) {
                continue;
            }
            WeChatRefundInfoVO weChatRefundInfoVO = weChatRefundService.queryAppointmentOrderRefundStatus(refundOrderInfoVO.getOutRefundNo());
            if (StringUtils.isNotBlank(weChatRefundInfoVO.getStatus())
                    && RefundStatusEnum.SUCCESS.getInfo().equals(weChatRefundInfoVO.getStatus())) {
                List<String> orderNoList = Collections.singletonList(refundOrderInfoVO.getOrderNo());
                LocalDateTime successTime = StringUtils.isBlank(weChatRefundInfoVO.getSuccessTime()) ? LocalDateTime.now() : LocalDateTime.parse(weChatRefundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME);
                refundInfoMapper.updateBatchRefundStatus(refundOrderInfoVO.getOrderNo(), successTime, weChatRefundInfoVO.getStatus());
                appointmentOrderMapper.updateBatchAppointmentOrderStatus(orderNoList, OrderStatusEnum.REFUNDED.getInfo());
                if (Objects.nonNull(refundOrderInfoVO.getAppointmentLimitCount()) && StringUtils.equals(AppointmentOrderTypeEnum.OTHER.getInfo(), refundOrderInfoVO.getAppointmentOrderType())) {
                    String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + refundOrderInfoVO.getNurseStationItemId() + "_" + refundOrderInfoVO.getServiceDate() + "_" + refundOrderInfoVO.getServiceStartTime();
                    RedisAtomicLong redisAtomicLong = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
                    if (redisAtomicLong.get() >= 0 && redisAtomicLong.get() < refundOrderInfoVO.getAppointmentLimitCount()) {
                        redisAtomicLong.incrementAndGet();
                        successList.add(refundOrderInfoVO);
                    }
                }
            }
        }
        return successList;
    }

    /**
     * 处理退款成功的商品订单信息
     *
     * @param refundGoodsOrderLit 商品退款订单信息
     */
    private void processGoodsRefundInfo(List<RefundOrderInfoVO> refundGoodsOrderLit) {
        List<String> orderNoList = Lists.newArrayList();
        for (RefundOrderInfoVO refundOrderInfoVO : refundGoodsOrderLit) {
            if (StringUtils.isBlank(refundOrderInfoVO.getOrderNo())
                    || StringUtils.isBlank(refundOrderInfoVO.getOutRefundNo()) || StringUtils.isBlank(refundOrderInfoVO.getBuySource())) {
                continue;
            }
            WeChatRefundInfoVO weChatRefundInfoVO = weChatRefundService.queryGoodsOrderRefundStatus(refundOrderInfoVO.getOutRefundNo(), refundOrderInfoVO.getBuySource());
            if (StringUtils.isNotBlank(weChatRefundInfoVO.getStatus())
                    && RefundStatusEnum.SUCCESS.getInfo().equals(weChatRefundInfoVO.getStatus())) {
                orderNoList.add(refundOrderInfoVO.getOrderNo());
            }
            log.info("修改商品订单表状态和增加库存数量，订单编号=====> {}, 商品属性明细表id======> {}", refundOrderInfoVO.getOrderNo(), refundOrderInfoVO.getGoodsAttributeDetailsId());
            LocalDateTime successTime = StringUtils.isBlank(weChatRefundInfoVO.getSuccessTime()) ? LocalDateTime.now() : LocalDateTime.parse(weChatRefundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME);
            refundInfoMapper.updateBatchRefundStatus(refundOrderInfoVO.getOrderNo(), successTime, weChatRefundInfoVO.getStatus());
            if (StringUtils.isNotBlank(refundOrderInfoVO.getOrderType()) && !OrderTypeEnum.HEALTH_CONSULTATION.getInfo().equals(refundOrderInfoVO.getOrderType())) {
                String stockNum = StringUtils.isBlank(refundOrderInfoVO.getGoodsCount()) ? "0" : refundOrderInfoVO.getGoodsCount();
                goodsStockService.addGoodsStockInfo(refundOrderInfoVO.getOrderNo(), refundOrderInfoVO.getGoodsAttributeDetailsId(), Integer.parseInt(stockNum));
                if (Objects.nonNull(refundOrderInfoVO.getCouponId()) && Objects.nonNull(refundOrderInfoVO.getPatientId())) {
                    patientCouponReceiveMapper.updatePatientCouponUseStatus(refundOrderInfoVO.getPatientId(), refundOrderInfoVO.getCouponId(), CouponUseStatusEnum.NOT_USED.getInfo());
                }
            }
        }
        if (CollectionUtils.isNotEmpty(orderNoList)) {
            goodsOrderMapper.updateBatchGoodsOrderStatus(orderNoList, OrderStatusEnum.REFUNDED.getInfo());
        }
    }

    /**
     * 处理退款成功的专家咨询订单信息
     *
     * @param refundGoodsOrderLit 专家咨询订单信息
     */
    private void processHealthConsultationRefund(List<RefundOrderInfoVO> refundGoodsOrderLit) {
        List<String> orderNoList = Lists.newArrayList();
        for (RefundOrderInfoVO refundOrderInfoVO : refundGoodsOrderLit) {
            if (StringUtils.isBlank(refundOrderInfoVO.getOrderNo())
                    || StringUtils.isBlank(refundOrderInfoVO.getOutRefundNo()) || StringUtils.isBlank(refundOrderInfoVO.getBuySource())) {
                continue;
            }
            WeChatRefundInfoVO weChatRefundInfoVO = weChatRefundService.queryGoodsOrderRefundStatus(refundOrderInfoVO.getOutRefundNo(), refundOrderInfoVO.getBuySource());
            if (StringUtils.isNotBlank(weChatRefundInfoVO.getStatus())
                    && RefundStatusEnum.SUCCESS.getInfo().equals(weChatRefundInfoVO.getStatus())) {
                orderNoList.add(refundOrderInfoVO.getOrderNo());
            }
            LocalDateTime successTime = StringUtils.isBlank(weChatRefundInfoVO.getSuccessTime()) ? LocalDateTime.now() : LocalDateTime.parse(weChatRefundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME);
            refundInfoMapper.updateBatchRefundStatus(refundOrderInfoVO.getOrderNo(), successTime, weChatRefundInfoVO.getStatus());
        }
        if (CollectionUtils.isNotEmpty(orderNoList)) {
            goodsOrderMapper.updateBatchGoodsOrderStatus(orderNoList, OrderStatusEnum.REFUNDED.getInfo());
        }
    }

    /**
     * 处理退款成功的学习培训订单信息
     *
     * @param trainingRefundOrderList 学习培训订单集合
     */
    private void handleRefundTrainingOrderInfo(List<TrainingRefundOrderVO> trainingRefundOrderList) {
        List<String> orderNoList = Lists.newArrayList();
        for (TrainingRefundOrderVO refundOrderVO : trainingRefundOrderList) {
            if (StringUtils.isBlank(refundOrderVO.getTrainingOrderNo()) || StringUtils.isBlank(refundOrderVO.getOutRefundNo())) {
                continue;
            }
            WeChatRefundInfoVO weChatRefundInfoVO = weChatRefundService.queryGoodsOrderRefundStatus(refundOrderVO.getOutRefundNo(), BuySourceEnum.TRAINING.getInfo());
            if (StringUtils.isNotBlank(weChatRefundInfoVO.getStatus())
                    && RefundStatusEnum.SUCCESS.getInfo().equals(weChatRefundInfoVO.getStatus())) {
                orderNoList.add(refundOrderVO.getTrainingOrderNo());
            }
            log.info("修改学习培训订单微信退款状态和本地订单状态，订单编号=====> {}, 退款单号======> {}", refundOrderVO.getTrainingOrderNo(), refundOrderVO.getOutRefundNo());
            LocalDateTime successTime = StringUtils.isBlank(weChatRefundInfoVO.getSuccessTime()) ? LocalDateTime.now() : LocalDateTime.parse(weChatRefundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME);
            refundInfoMapper.updateBatchRefundStatus(refundOrderVO.getTrainingOrderNo(), successTime, weChatRefundInfoVO.getStatus());
        }
        if (CollectionUtils.isNotEmpty(orderNoList)) {
            trainingOrderMapper.updateBatchTrainingOrderStatus(orderNoList, TrainingOrderStatusEnum.REFUNDED.getInfo());
        }
    }
}
