package com.seamew.lottery.domain.strategy.service.draw.impl;

import com.alibaba.fastjson2.JSON;
import com.seamew.lottery.common.Constants;
import com.seamew.lottery.domain.strategy.model.res.AwardStockResult;
import com.seamew.lottery.domain.strategy.model.vo.AwardDeductStockVO;
import com.seamew.lottery.domain.strategy.service.algorithm.IDrawAlgorithm;
import com.seamew.lottery.domain.strategy.service.draw.AbstractDrawBase;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @Author: seamew
 * @Title: DrawExecImpl
 * @CreateTime: 2023年02月14日 18:43:00
 * @Description: 抽奖过程方法实现
 * @Version: 1.0
 */
@Service("drawExec")
@Slf4j
public class DrawExecImpl extends AbstractDrawBase {

    @Override
    protected List<String> queryExcludeAwardIds(Long strategyId) {
        List<String> awardList = strategyRepository.queryNoStockStrategyAwardList(strategyId);
        log.info("执行抽奖策略 strategyId：{}，无库存排除奖品列表ID集合 awardList：{}", strategyId, JSON.toJSONString(awardList));
        return awardList;
    }

    @Override
    protected AwardStockResult drawAlgorithm(Long strategyId, IDrawAlgorithm drawAlgorithm, List<String> excludeAwardIds) {
        // 执行抽奖
        String awardId = drawAlgorithm.randomDraw(strategyId, excludeAwardIds);

        // 判断抽奖结果
        if (StringUtils.isEmpty(awardId)) {
            return new AwardStockResult(Constants.ResponseCode.LOSING_DRAW.getCode(), Constants.ResponseCode.LOSING_DRAW.getInfo());
        }

        /*
         * 扣减库存，暂时采用数据库行级锁的方式进行扣减库存，后续优化为 Redis 分布式锁扣减 decr/incr
         * 注意：通常数据库直接锁行记录的方式并不能支撑较大体量的并发，但此种方式需要了解，
         * 因为在分库分表下的正常数据流量下的个人数据记录中，是可以使用行级锁的，因为他只影响到自己的记录，不会影响到其他人
         */
        return strategyRepository.deductStockByRedis(strategyId, awardId);
    }

    @Override
    public void updateAwardStock(AwardDeductStockVO awardDeductStockVO) {
        strategyRepository.updateAwardStock(awardDeductStockVO);
    }

    @Override
    public void recoverAwardCacheStockByRedis(String tokenKey) {
        strategyRepository.recoverAwardCacheStockByRedis(tokenKey);
    }
}
