package cn.iocoder.yudao.module.member.service.amount;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoCardVO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.refund.RefundDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.card.CardMapper;
import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.refund.IntegralRefundMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.service.money.MoneyService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.member.service.amount.LockManager.getUserLock;

/**
 * 现金充值 Service 实现类
 *
 * @author 开发账号
 */
@Service
@Slf4j
public class CashRechargeServiceImpl implements CashRechargeService {

    @Resource
    private MemberUserMapper userMapper;
    @Resource
    private DishOrderMapper dishOrderMapper;
    @Resource
    private CardMapper cardMapper;
    @Resource
    private IntegralRefundMapper refundMapper;
    @Resource
    private MemberGroupMapper memberGroupMapper;
    @Resource
    private MoneyService moneyService;

    @Resource
    private StringRedisTemplate cashRechargeRedisTemplate;


    @Override
    public void rechargeByAdmin(List<Long> userIds, Long groupId, BigDecimal money, Long storeId,Boolean group) {

        Set<Long> memberSet = new HashSet<>();
        MemberGroupDO memberGroupDO = memberGroupMapper.selectById(groupId);
        if (group) {
            memberSet.addAll(memberGroupMapper.getMemberList(groupId));
        } else {
            memberSet.addAll(userIds);
        }
        //明细列表
        ArrayList<CardDO> addList = new ArrayList<>();
        List<Long> memberList = new ArrayList<>(memberSet);
        for (Long userId : memberList) {

            BigDecimal wxNewMoney;
            BigDecimal newMoney;
            BigDecimal cashNewAmount;
            String name;

            synchronized (getUserLock(userId)) {
                MemberUserDO memberUserDO = userMapper.selectByIdForUpdate(userId);
                //金额变动
                BigDecimal oldMoney = memberUserDO.getMoney();
                newMoney = oldMoney.add(money);
                memberUserDO.setMoney(newMoney);

                if(newMoney.compareTo(BigDecimal.ZERO) >= 0){
                    if(oldMoney.compareTo(BigDecimal.ZERO) < 0){
                        memberUserDO.setCashAmount(newMoney);
                    }else {
                        memberUserDO.setCashAmount(memberUserDO.getCashAmount().add(money));
                    }
                }
                userMapper.updateById(memberUserDO);
                wxNewMoney = memberUserDO.getWxAmount();
                cashNewAmount = memberUserDO.getCashAmount();
                name = memberUserDO.getNickname();

            }

            //记录明细
            CardDO add = new CardDO();
            add.setUserId(userId);
            add.setFlag(CardDO.ADD);
            add.setChangeMoney(money);
            add.setType(CostTypeEnum.ADMIN_PAY.getCode());
            add.setCashAmount(cashNewAmount);
            add.setWxAmount(wxNewMoney);
            add.setCarteenId(storeId);
            add.setGroupId(groupId);
            add.setMoney(newMoney);
            add.setGroupName(ObjectUtil.isNotEmpty(memberGroupDO)?memberGroupDO.getName():null);
            addList.add(add);

            //更新缓存
            String redisKey = "USER_" + userId;
            AppUserInfoCardVO appUserInfoCardVO = new AppUserInfoCardVO();
            appUserInfoCardVO.setName(name);
            appUserInfoCardVO.setMoney(newMoney);
            cashRechargeRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(appUserInfoCardVO));

        }

        //处理订单
        handleOrderCash(memberList, money, storeId);

        //批量添加
        cardMapper.insertBatch(addList);
    }


    void handleOrderCash(List<Long> userIds, BigDecimal money, Long storeId) {
        ArrayList<DishOrderDO> updateList = new ArrayList<>();
        List<Long> refundOrder = getRefundOrder();
        //查询出所有未完全支付订单
        for (Long userId : userIds) {
            BigDecimal cashMoney = money;

            List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(Wrappers.<DishOrderDO>lambdaQuery()
                    .eq(DishOrderDO::getUserId, userId).eq(DishOrderDO::getOrderStatus, DishOrderDO.TOCOMPLETE)
//                    .eq(DishOrderDO::getStoreId, storeId)
                    );

            if (CollectionUtil.isNotEmpty(dishOrderDOS)) {
                for (DishOrderDO dishOrderDO : dishOrderDOS) {
                    BigDecimal payAmount = dishOrderDO.getPayAmount();
                    if (payAmount.compareTo(cashMoney) <= 0) {
                        dishOrderDO.setOrderStatus(DishOrderDO.COMPLETE);
                        dishOrderDO.setPayAmount(BigDecimal.ZERO);
                        dishOrderDO.setRefundAmount(dishOrderDO.getRefundAmount().add(payAmount));
                        if (refundOrder.contains(dishOrderDO.getId())) {
                            dishOrderDO.setRefundAmount(BigDecimal.ZERO);
                        }
                        dishOrderDO.setCashAmount(dishOrderDO.getCashAmount().add(payAmount));
                        cashMoney = cashMoney.subtract(payAmount);
                        updateList.add(dishOrderDO);
                    } else {
                        dishOrderDO.setPayAmount(payAmount.subtract(cashMoney));
                        dishOrderDO.setRefundAmount(dishOrderDO.getRefundAmount().add(cashMoney));
                        if (refundOrder.contains(dishOrderDO.getId())) {
                            dishOrderDO.setRefundAmount(BigDecimal.ZERO);
                        }
                        dishOrderDO.setCashAmount(dishOrderDO.getCashAmount().add(cashMoney));
                        updateList.add(dishOrderDO);
                        break;
                    }
                }
            }
        }
        if (CollectionUtil.isNotEmpty(updateList)) {
            dishOrderMapper.updateBatch(updateList);
        }

    }

    public List<Long> getRefundOrder() {
        List<RefundDO> refundDOS = refundMapper.selectList(Wrappers.<RefundDO>lambdaQuery().in(RefundDO::getStatus, Arrays.asList("2", "3")));
        ArrayList<Long> orderIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(refundDOS)) {
            List<Long> collect = refundDOS.stream().map(RefundDO::getOrderId).collect(Collectors.toList());
            orderIds.addAll(collect);
        }

        return orderIds;
    }
}
