package com.hzs.activity.draw.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.activity.draw.mapper.AcDrawRewardNumMapper;
import com.hzs.activity.draw.param.AcDrawRewardNumParam;
import com.hzs.activity.draw.service.IAcDrawRewardNumDetailService;
import com.hzs.activity.draw.service.IAcDrawRewardNumService;
import com.hzs.activity.draw.service.IAcDrawRuleConfigService;
import com.hzs.common.core.constant.ActivityFieldConstants;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.constant.SystemFieldConstants;
import com.hzs.common.core.enums.EActType;
import com.hzs.common.core.enums.EOrderPrefix;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.CommonUtil;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.activity.draw.AcDrawRewardNum;
import com.hzs.common.domain.activity.draw.AcDrawRewardNumDetail;
import com.hzs.common.domain.activity.draw.AcDrawRuleConfig;
import com.hzs.common.domain.activity.draw.ext.AcDrawRewardNumExt;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.member.account.IMemberAccountServiceApi;
import com.hzs.member.base.IMemberServiceApi;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 会员可抽奖次数记录 服务实现类
 */
@Service
public class AcDrawRewardNumServiceImpl extends ServiceImpl<AcDrawRewardNumMapper, AcDrawRewardNum> implements IAcDrawRewardNumService {

    @DubboReference
    IMemberAccountServiceApi memberAccountServiceApi;
    @DubboReference
    IMemberServiceApi memberServiceApi;

    private IAcDrawRuleConfigService acDrawRuleConfigService;

    private RedisService redisService;

    private IAcDrawRewardNumDetailService acDrawRewardNumDetailService;

    @Autowired
    public void setAcDrawRewardNumDetailService(IAcDrawRewardNumDetailService acDrawRewardNumDetailService) {
        this.acDrawRewardNumDetailService = acDrawRewardNumDetailService;
    }

    @Autowired
    public void setAcDrawRuleConfigService(IAcDrawRuleConfigService acDrawRuleConfigService) {
        this.acDrawRuleConfigService = acDrawRuleConfigService;
    }

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Override
    public AcDrawRewardNum queryAcDrawRewardNum(AcDrawRewardNumParam acDrawRewardNumParam) {
        QueryWrapper<AcDrawRewardNum> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(MemberFieldConstants.PK_MEMBER, acDrawRewardNumParam.getPkMember());
        queryWrapper.eq(SystemFieldConstants.PK_COUNTRY, acDrawRewardNumParam.getPkCountry());
        queryWrapper.eq(ActivityFieldConstants.PK_BASE_ID, acDrawRewardNumParam.getPkBaseId());
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public List<AcDrawRewardNumExt> queryDrawRewardExtNumByCondition(AcDrawRewardNumParam acDrawRewardNumParam) {
        return baseMapper.queryDrawRewardExtNumByCondition(acDrawRewardNumParam);
    }

    @Override
    public Boolean updateAcDrawRewardNum(AcDrawRewardNum acDrawRewardNum) {
        String key = CacheConstants.DRAW_REWARD_NUMBER + acDrawRewardNum.getPkMember();
        boolean flag = redisService.lockKeyMany(key);
        try {
            if (flag) {
                UpdateWrapper<AcDrawRewardNum> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq(SystemFieldConstants.PK_ID, acDrawRewardNum.getPkId());
                updateWrapper.gt(ActivityFieldConstants.AVAILABLE_SURPLUS_NUM, 0);
                updateWrapper.set(ActivityFieldConstants.AVAILABLE_USED_NUM, acDrawRewardNum.getAvailableUsedNum() + 1);
                updateWrapper.set(ActivityFieldConstants.AVAILABLE_SURPLUS_NUM, acDrawRewardNum.getAvailableSurplusNum() - 1);
                update(updateWrapper);
            }
        } finally {
            redisService.unlock(key);
        }
        return null;
    }

    @Override
    public List<CuMemberAccountExt> queryMemberAccountByCondition(CuMemberAccount cuMemberAccount) {
        return memberAccountServiceApi.queryMemberAccountByCondition(cuMemberAccount).getData();
    }

    @Override
    public AcDrawRewardNumExt queryDrawRewardNumByCondition(AcDrawRewardNumParam acDrawRewardNumParam) {
        return baseMapper.queryDrawRewardNumByCondition(acDrawRewardNumParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payDrawRewardNum(CuMemberAccountExt cuMemberAccountExt, Integer payNum, AcDrawRewardNumExt acDrawRewardNumExt) {
        // 更新次数，可用总次数 + 次数 剩余可抽奖总次数 +次数 已用用次数-次数 可用总次数-次数
        updateDrawRewardNum(payNum, acDrawRewardNumExt);
        // 更新会员账户、交易流水
        if (!memberServiceApi.updateCuMemberAccountByDraw(cuMemberAccountExt, ComputeUtil.computeMultiply(acDrawRewardNumExt.getPayMoney(), payNum)).getData()) {
            throw new RuntimeException();
        }
    }

    private void updateDrawRewardNum(Integer payNum, AcDrawRewardNumExt acDrawRewardNumExt) {
        UpdateWrapper<AcDrawRewardNum> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq(SystemFieldConstants.PK_ID, acDrawRewardNumExt.getPkId());
//        updateWrapper.set("TOTAL_USED_NUM", acDrawRewardNumExt.getTotalUsedNum() + payNum);
        updateWrapper.set("TOTAL_SURPLUS_NUM", acDrawRewardNumExt.getTotalSurplusNum() - payNum);
        updateWrapper.set("AVAILABLE_NUM", acDrawRewardNumExt.getAvailableNum() + payNum);
        updateWrapper.set("AVAILABLE_SURPLUS_NUM", acDrawRewardNumExt.getAvailableSurplusNum() + payNum);
        update(updateWrapper);
    }

    @Override
    public String confirmDrawRewardPayNum(AcDrawRewardNumParam acDrawRewardNumParam, AcDrawRewardNumExt acDrawRewardNum) {
        String orderCode = CommonUtil.createSerialNumber(EOrderPrefix.ON_LINE.getValue());
        acDrawRewardNumParam.setActCode(orderCode);
        acDrawRewardNumParam.setActType(EActType.LOTTERY_DRAW.getValue());
        acDrawRewardNumParam.setAcDrawRewardNum(acDrawRewardNum);
        // 放入redis
        redisService.setCacheObject(CacheConstants.TEMP_ORDER + acDrawRewardNumParam.getPkMember() + orderCode, acDrawRewardNumParam, CacheConstants.MEMBER_REFRESH_TIME, TimeUnit.MINUTES);
        return orderCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean giveMemberDrawNum(SaOrderExt saOrderExt) {
        AcDrawRuleConfig acDrawRuleConfig = AcDrawRuleConfig.builder().orderType(saOrderExt.getOrderType()).orderAmount(saOrderExt.getOrderAmount()).orderAchieve(saOrderExt.getOrderAchieve()).build();
        acDrawRuleConfig.setPkCountry(saOrderExt.getPkCountry());
        List<AcDrawRuleConfig> acDrawRuleConfigList = acDrawRuleConfigService.queryDrawRuleConfigByCondition(acDrawRuleConfig);
        if (CollectionUtil.isNotEmpty(acDrawRuleConfigList)) {
            // 保存抽奖次数
            for (AcDrawRuleConfig drawRuleConfig : acDrawRuleConfigList) {
                // 购买人
                updateMemberDrawNum(saOrderExt.getPkMember(), saOrderExt, drawRuleConfig);
                // 推荐人
                updateMemberDrawNum(saOrderExt.getPkReference(), saOrderExt, drawRuleConfig);
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean backGiveMemberDrawNum(SaOrderExt saOrderExt) {
        // 查询订单是否赠送过抽奖次数
        List<AcDrawRewardNumDetail> drawRewardNumDetailList = acDrawRewardNumDetailService.queryAcDrawRewardNumBySaOrder(saOrderExt.getPkId());
        if (CollectionUtil.isNotEmpty(drawRewardNumDetailList)) {
            for (AcDrawRewardNumDetail drawRewardNumDetail : drawRewardNumDetailList) {
                AcDrawRewardNum acDrawRewardNum = baseMapper.selectById(drawRewardNumDetail.getPkDrawRewardNum());
                acDrawRewardNum.setTotalNum(acDrawRewardNum.getTotalNum() - drawRewardNumDetail.getGiveNum());
                acDrawRewardNum.setTotalSurplusNum(acDrawRewardNum.getTotalSurplusNum() - drawRewardNumDetail.getGiveNum());
                acDrawRewardNum.setPkModified(saOrderExt.getPkCreator());
                acDrawRewardNum.setModifiedTime(DateUtils.currentDateTime());
                updateById(acDrawRewardNum);
                drawRewardNumDetail.setPkModified(saOrderExt.getPkCreator());
                acDrawRewardNumDetailService.deleteAcDrawRewardNumDetail(drawRewardNumDetail);
            }
        }
        return true;
    }

    private void updateMemberDrawNum(Long pkMember, SaOrderExt saOrderExt, AcDrawRuleConfig drawRuleConfig) {
        // 验证是否已经存在抽奖，存在的修改
        AcDrawRewardNum acDrawRewardNum = queryAcDrawRewardNum(AcDrawRewardNumParam.builder().pkMember(pkMember)
                .pkBaseId(drawRuleConfig.getPkBaseId()).pkCountry(saOrderExt.getPkCountry()).build());
        if (acDrawRewardNum == null) {
            acDrawRewardNum = AcDrawRewardNum.builder()
                    .pkBaseId(drawRuleConfig.getPkBaseId())
                    .pkMember(pkMember)
                    .totalNum(drawRuleConfig.getGiveNumber())
                    .totalSurplusNum(drawRuleConfig.getGiveNumber())
                    .build();
            acDrawRewardNum.setPkCountry(saOrderExt.getPkCountry());
            acDrawRewardNum.setPkCreator(saOrderExt.getPkCreator());
            save(acDrawRewardNum);
        } else {
            acDrawRewardNum.setTotalNum(acDrawRewardNum.getTotalNum() + drawRuleConfig.getGiveNumber());
            acDrawRewardNum.setTotalSurplusNum(acDrawRewardNum.getTotalSurplusNum() + drawRuleConfig.getGiveNumber());
            acDrawRewardNum.setPkModified(saOrderExt.getPkCreator());
            acDrawRewardNum.setModifiedTime(DateUtils.currentDateTime());
            updateById(acDrawRewardNum);
        }
        acDrawRewardNumDetailService.saveAcDrawRewardNumDetail(acDrawRewardNum, drawRuleConfig.getGiveNumber(), saOrderExt);
    }
}
