package com.liquidnet.service.platform.service.impl.adam;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.common.cache.redis.util.AbstractRedisUtil;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.vo.AdamMemberOrderVo;
import com.liquidnet.service.adam.dto.vo.AdamUserInfoVo;
import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo;
import com.liquidnet.service.adam.entity.AdamMemberOrder;
import com.liquidnet.service.adam.entity.AdamMemberRefund;
import com.liquidnet.service.adam.entity.AdamUserMember;
import com.liquidnet.service.adam.mapper.AdamMemberOrderMapper;
import com.liquidnet.service.adam.mapper.AdamMemberRefundMapper;
import com.liquidnet.service.adam.mapper.AdamUserMemberMapper;
import com.liquidnet.service.candy.constant.CandyRedisConst;
import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto;
import com.liquidnet.service.candy.entity.CandyUserCoupon;
import com.liquidnet.service.candy.mapper.CandyUserCouponMapper;
import com.liquidnet.service.feign.stone.api.FeignStoneIntegralClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Service
public class PlatformMemberRefundService extends ServiceImpl<AdamMemberRefundMapper, AdamMemberRefund> {
    @Autowired
    private AdamMemberOrderMapper adamMemberOrderMapper;
    @Autowired
    private AdamUserMemberMapper adamUserMemberMapper;
    @Autowired
    private CandyUserCouponMapper candyUserCouponMapper;

    @Autowired
    private RedisDataSourceUtil redisDataSourceUtil;

    @Autowired
    FeignStoneIntegralClient feignStoneIntegralClient;

    public boolean refundProcessing(HttpServletRequest request) {
        String refundNo = request.getParameter("orderRefundCode");
        String refundAt = request.getParameter("refundAt");
        String payNo = request.getParameter("refundCode");
        String refundError = request.getParameter("refundError");
        String refundAmt = request.getParameter("refundPrice");
        int status = Integer.parseInt(request.getParameter("status"));

        AdamMemberRefund memberRefund = this.getOne(Wrappers.lambdaQuery(AdamMemberRefund.class)
                .eq(AdamMemberRefund::getRefundNo, refundNo));

        if (null == memberRefund) {
            log.warn("会员退款回调处理失败:订单不存在[payNo:{},refundNo:{}]", payNo, refundNo);
            return false;
        }
        if (memberRefund.getRefundState() != 9) {
            log.warn("会员退款回调处理失败:订单已处理[payNo:{},refundNo:{}]", payNo, refundNo);
            return true;
        }

        LocalDateTime now = LocalDateTime.now();

        LambdaUpdateWrapper<AdamMemberRefund> memberRefundLambdaUpdateWrapper = Wrappers.lambdaUpdate(AdamMemberRefund.class)
                .eq(AdamMemberRefund::getRefundNo, refundNo);
        memberRefundLambdaUpdateWrapper.set(AdamMemberRefund::getRefundAt, refundAt);
        memberRefundLambdaUpdateWrapper.set(AdamMemberRefund::getRepayReason, refundError);
        memberRefundLambdaUpdateWrapper.set(AdamMemberRefund::getUpdatedAt, now);

        switch (status) {
            case 0:// 失败
                memberRefundLambdaUpdateWrapper.set(AdamMemberRefund::getRefundState, 3);
                return this.update(memberRefundLambdaUpdateWrapper);
            case 1:// 成功
                memberRefundLambdaUpdateWrapper.set(AdamMemberRefund::getRefundState, 1);
                if (this.update(memberRefundLambdaUpdateWrapper)) {

                    this.refundSuccProcessing(memberRefund.getOrderNo(), now, refundAmt);

                    return true;
                } else {
                    return false;
                }
            default:
                log.warn("会员退款回调处理失败:未知的状态[orderNo:{},refundNo:{},status:{}]", memberRefund.getOrderNo(), refundNo, status);
                return false;
        }
    }

    /* -------------------------------------------------------------------------- */

    private void refundSuccProcessing(String orderNo, LocalDateTime now, String refundAmt) {
        AdamMemberOrder memberOrder = adamMemberOrderMapper.selectOne(Wrappers.lambdaUpdate(AdamMemberOrder.class).eq(AdamMemberOrder::getOrderNo, orderNo));
        List<String> removeUcouponIdList = null;
        LocalDateTime newExpiryAt = null;
        boolean syncVo = false;

        AbstractRedisUtil redisAdamUtil = redisDataSourceUtil.getRedisAdamUtil();
        AbstractRedisUtil redisCandyUtil = redisDataSourceUtil.getRedisCandyUtil();

        {// 同步用户端信息
            // 同步更新REDIS会员订单信息
            String moKey = AdamRedisConst.INFO_MEMBER_ORDER + memberOrder.getUid();
            ArrayList<AdamMemberOrderVo> vos = (ArrayList<AdamMemberOrderVo>) redisAdamUtil.get(moKey);
            if (!CollectionUtils.isEmpty(vos)) {
                int idx = IntStream.range(0, vos.size()).filter(i -> vos.get(i).getOrderNo().equals(memberOrder.getOrderNo())).findFirst().orElse(-1);
                AdamMemberOrderVo vo = vos.get(idx);
                vo.setState(5);
                vo.setUpdatedAt(now);
                vos.set(idx, vo);
                syncVo = redisAdamUtil.set(moKey, vos);
                log.info("###会员退款回调处理成功:更新REDIS会员订单信息{}[orderNo:{},uid:{}]", syncVo ? "成功" : "失败", orderNo, memberOrder.getUid());
            }

            String umKey = AdamRedisConst.INFO_USER_MEMBER.concat(memberOrder.getUid());
            AdamUserMemberVo userMemberVo = (AdamUserMemberVo) redisAdamUtil.get(umKey);

            // 用户会员权益券信息
            String uckey = CandyRedisConst.BASIC_USER_COUPON.concat(memberOrder.getUid());
            List<CandyUserCouponBasicDto> userCouponBasicDtoList = (List<CandyUserCouponBasicDto>) redisCandyUtil.get(uckey);

            // 同步更新REDIS会员信息
            if (null != userMemberVo) {
                if (userMemberVo.getState() == 1) {// 非拉黑用户，则更新到期时间为减去订单标记的会员有效期的日期
                    LocalDateTime expiryAt = userMemberVo.getExpiryAt();
                    newExpiryAt = expiryAt.minusDays(memberOrder.getDays());

                    LocalDate nowDate = now.toLocalDate();
                    LocalDate newExpiryDate = newExpiryAt.toLocalDate();
                    if (newExpiryDate.isEqual(nowDate)) {// 新的过期时间如果和当前时间为同一天，则重置到期时间为当天00:00:00
                        newExpiryAt = now.withHour(0).withMinute(0).withSecond(0);
                    }

                    userMemberVo.setExpiryAt(newExpiryAt);
                    userMemberVo.setUpdatedAt(now);

                    syncVo = redisAdamUtil.set(umKey, userMemberVo);
                    log.info("###会员退款回调处理成功:更新REDIS会员信息{}[orderNo:{},uid:{}]", syncVo ? "成功" : "失败", orderNo, memberOrder.getUid());

                    // 同步更新MYSQL会员信息
                    AdamUserMember updateInfoUserMember = new AdamUserMember();
                    updateInfoUserMember.setExpiryAt(newExpiryAt);
                    updateInfoUserMember.setUpdatedAt(now);
                    updateInfoUserMember.setComment("R");
                    int updateRst = adamUserMemberMapper.update(updateInfoUserMember, Wrappers.lambdaUpdate(AdamUserMember.class).eq(AdamUserMember::getUid, memberOrder.getUid()));
                    log.info("###会员退款回调处理成功:更新DB会员信息{}[orderNo:{},uid:{}]", updateRst <= 0 ? "失败" : "成功", orderNo, memberOrder.getUid());

                    if (!CollectionUtils.isEmpty(userCouponBasicDtoList)) {
                        removeUcouponIdList = userCouponBasicDtoList.stream()
                                .filter(r -> (r.getExclusive() == 1 && r.getDuedAt().compareTo(expiryAt) == 0))
                                .map(CandyUserCouponBasicDto::getUcouponId)
                                .collect(Collectors.toList());
                    }
                } else if (userMemberVo.getState() == 2) {// 拉黑用户
                    if (!CollectionUtils.isEmpty(userCouponBasicDtoList)) {
                        removeUcouponIdList = userCouponBasicDtoList.stream()
                                .filter(r -> (r.getExclusive() == 1))
                                .map(CandyUserCouponBasicDto::getUcouponId)
                                .collect(Collectors.toList());
                    }
                }
            }
            // 同步删除REDIS用户会员权益券信息
            if (!CollectionUtils.isEmpty(removeUcouponIdList)) {
                List<String> finalRemoveUcouponIdList = removeUcouponIdList;
                userCouponBasicDtoList.removeIf(r -> finalRemoveUcouponIdList.contains(r.getUcouponId()));
                redisCandyUtil.set(uckey, userCouponBasicDtoList);

                // 同步更新MYSQL用户会员权益券信息
                LambdaUpdateWrapper<CandyUserCoupon> candyUserCouponLambdaUpdateWrapper = Wrappers.lambdaUpdate(CandyUserCoupon.class);
                candyUserCouponLambdaUpdateWrapper.in(CandyUserCoupon::getUcouponId, removeUcouponIdList.toArray()).eq(CandyUserCoupon::getState, 1);
                CandyUserCoupon updateInfoUserCoupon = new CandyUserCoupon();
                updateInfoUserCoupon.setState(2);
                updateInfoUserCoupon.setUpdatedAt(now);
                updateInfoUserCoupon.setOperator("system.vip.refund");
                int updateRst = candyUserCouponMapper.update(updateInfoUserCoupon, candyUserCouponLambdaUpdateWrapper);
                log.info("###会员退款回调处理成功:更新DB会员权益券信息{}[orderNo:{},uid:{}]", updateRst <= 0 ? "失败" : "成功", orderNo, memberOrder.getUid());
            }
        }

        // 同步更新MYSQL会员订单信息
        AdamMemberOrder updateInfoMemberOrder = new AdamMemberOrder();
        updateInfoMemberOrder.setMid(memberOrder.getMid());
        updateInfoMemberOrder.setState(5);
        updateInfoMemberOrder.setUpdatedAt(now);
        int updateRst = adamMemberOrderMapper.updateById(updateInfoMemberOrder);
        log.info("###会员退款回调处理成功:更新DB订单信息{}[orderNo:{}]", updateRst <= 0 ? "失败" : "成功", orderNo);

        feignStoneIntegralClient.de2111(memberOrder.getUid(), new BigDecimal(refundAmt).intValue(), "会员注销");
    }
}
