package com.diaoyun.zion.chinafrica.service.impl;

import com.diaoyun.zion.chinafrica.constant.KeyConstant;
import com.diaoyun.zion.chinafrica.dao.TbCfCouponDao;
import com.diaoyun.zion.chinafrica.dao.TbCfTakeCouponDao;
import com.diaoyun.zion.chinafrica.entity.TbCfCouponEntity;
import com.diaoyun.zion.chinafrica.entity.TbCfTakeCouponEntity;
import com.diaoyun.zion.chinafrica.service.TbCfCouponService;
import com.diaoyun.zion.chinafrica.vo.TbCfUserInfoVo;
import com.diaoyun.zion.chinafrica.vo.UserCouponVo;
import com.diaoyun.zion.master.base.Result;
import com.diaoyun.zion.master.base.StateConstant;
import com.diaoyun.zion.master.common.RedisCache;
import com.diaoyun.zion.master.common.TokenManager;
import com.diaoyun.zion.master.enums.ResultCodeEnum;
import com.diaoyun.zion.master.security.JwtTokenProvider;
import com.diaoyun.zion.master.util.IdUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 优惠券表Service实现类
 *
 * @author G
 * @date 2019-08-14 09:11:48
 */
@Service("tbCfCouponService")
public class TbCfCouponServiceImpl implements TbCfCouponService {
    private static Logger logger = LoggerFactory.getLogger(TbCfCouponServiceImpl.class);
    // new一个锁对象，注意此处必须声明成类对象，保持只有一把锁,ReentrantLock是Lock的唯一实现类
    private Lock lock = new ReentrantLock();

    @Autowired
    private TbCfCouponDao tbCfCouponDao;
    @Autowired
    private TbCfTakeCouponDao tbCfTakeCouponDao;

    @Resource(name = "redisTokenManager")
    private TokenManager tokenManager;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private HttpServletRequest request; //自动注入request
    @Resource
    private RedisCache<Map<String,TbCfCouponEntity>> redisCache;

    @Override
    public TbCfCouponEntity queryObject(String couponId) {
        return tbCfCouponDao.queryObject(couponId);
    }

    @Override
    public List<TbCfCouponEntity> queryList(Map<String, Object> map) {
        return tbCfCouponDao.queryList(map);
    }

    @Override
    public int queryTotal(Map<String, Object> map) {
        return tbCfCouponDao.queryTotal(map);
    }

    @Override
    public int save(TbCfCouponEntity tbCfCoupon) {
        tbCfCoupon.setCouponId(IdUtil.createIdbyUUID());
        return tbCfCouponDao.save(tbCfCoupon);
    }

    @Override
    public int update(TbCfCouponEntity tbCfCoupon) {
        return tbCfCouponDao.update(tbCfCoupon);
    }

    @Override
    public int delete(String couponId) {
        return tbCfCouponDao.delete(couponId);
    }

    @Override
    public int deleteBatch(String[] couponIds) {
        return tbCfCouponDao.deleteBatch(couponIds);
    }

    @Override
    public Result takeCoupon(String couponId) {
        Result<TbCfCouponEntity> result=new Result<>();
        //获取用户
        String token = jwtTokenProvider.resolveToken(request);
        TbCfUserInfoVo tbCfUserInfoVo = tokenManager.validate(token);
        //判断用户是否已经领取
        boolean takeFlag=false;//可以重复领取 repeatTakeCoupon(tbCfUserInfoVo.getUserId(),couponId);
        if(takeFlag) {
            result.setCode(ResultCodeEnum.ERROR.getCode()).setMessage("You have already received this coupon");
        } else {
            //  TODO 发放流程有bug，需要修复
            TbCfCouponEntity tbCfCouponEntity=grabCoupon(couponId);
            if(tbCfCouponEntity!=null) {
                //发放优惠券
                giveOutCoupon(tbCfUserInfoVo.getUserId(),tbCfCouponEntity);
                result.setData(tbCfCouponEntity);
                result.setMessage("Successfully received");
            } else {
                result.setCode(ResultCodeEnum.ERROR.getCode()).setMessage("The coupon has been snapped up");
            }
        }
        return result;
    }

    @Override
    public void takeCoupon(String couponId, String userId) {
        TbCfCouponEntity tbCfCouponEntity=grabCoupon(couponId);
        if(tbCfCouponEntity!=null) {
            //发放优惠券
            giveOutCoupon(userId,tbCfCouponEntity);
        } else {
        }
    }

    @Override
    public Result<UserCouponVo> getUserCoupons() {
        UserCouponVo userCouponVo = new UserCouponVo();
        //获取用户
        String token = jwtTokenProvider.resolveToken(request);
        TbCfUserInfoVo tbCfUserInfoVo = tokenManager.validate(token);
        //获取可以使用的优惠券
        List<TbCfCouponEntity> validCouponList = tbCfCouponDao.queryUserAvailableCoupon(tbCfUserInfoVo.getUserId(), new Date());
        //获取已使用的优惠券
        List<TbCfCouponEntity> usedCouponList = tbCfCouponDao.queryUserUsedCoupon(tbCfUserInfoVo.getUserId());
        //获取已过期的优惠券
        List<TbCfCouponEntity> expiredCouponList = tbCfCouponDao.queryUserExpiredoupon(tbCfUserInfoVo.getUserId(), new Date());
        userCouponVo.setExpiredCouponList(expiredCouponList);
        userCouponVo.setUsedCouponList(usedCouponList);
        userCouponVo.setValidCouponList(validCouponList);
        return new Result<>(userCouponVo);
    }

    @Override
    public Result<TbCfCouponEntity> queryCouponDetail(String couponId) {
        TbCfCouponEntity tbCfCouponEntity=tbCfCouponDao.queryObject(couponId);
        return new Result<>(tbCfCouponEntity);
    }

    /**
     * 抢优惠券
     * 若能抢到，则返回优惠券，否则返回空
     * @return
     */
    private TbCfCouponEntity grabCoupon(String couponId) {
        TbCfCouponEntity tbCfCouponEntity=null;
        //先从redis获取，若获取不到，则加入 TODO 修改的时候要同步修改redis

        lock.lock();
        try {
            Map<String,TbCfCouponEntity> couponMap=redisCache.get(KeyConstant.COUPON);
            if(couponMap==null||couponMap.get(couponId)==null) {
                tbCfCouponEntity =tbCfCouponDao.queryObject(couponId);
                //takecount 需要另外统计
                Integer takeCount=tbCfTakeCouponDao.queryTakeCount(couponId);
                tbCfCouponEntity.setTakeCount(takeCount);
                if(couponMap==null) {
                    couponMap=new HashMap<>();
                }
                couponMap.put(couponId,tbCfCouponEntity);
                setCouponCache(couponMap);
            } else {
                tbCfCouponEntity=couponMap.get(couponId);
            }
            //发放数量
            Integer quato=tbCfCouponEntity.getQuato();
            //发放数量>已经领取数量
            if(quato>tbCfCouponEntity.getTakeCount()) {
                //改动redis，
                tbCfCouponEntity.setTakeCount(tbCfCouponEntity.getTakeCount()+1);
                couponMap.put(couponId,tbCfCouponEntity);
                setCouponCache(couponMap);
            } else {
                tbCfCouponEntity=null;
                logger.debug("优惠券已被抢光");
            }
        }catch (Exception e) {
            logger.error(e.getMessage(),e);
        }finally {
            lock.unlock();
        }
        return tbCfCouponEntity;
    }

    /**
     * 设置优惠券缓存
     * @param couponMap 优惠券map
     */
    private void setCouponCache(Map<String, TbCfCouponEntity> couponMap) {
            redisCache.set(KeyConstant.COUPON,couponMap);
    }

    /**
     * 判断用户是否已经领取
     * @param couponId 优惠券id
     * @return true or false
     */
    private boolean repeatTakeCoupon(String userId,String couponId) {
        String takeId=tbCfTakeCouponDao.queryTakeByCouponId(userId,couponId);
        return !StringUtils.isBlank(takeId);
    }

    private void giveOutCoupon(String userId,TbCfCouponEntity tbCfCoupon) {

        //存储抢购记录
        TbCfTakeCouponEntity tbCfTakeCouponEntity = new TbCfTakeCouponEntity();
        tbCfTakeCouponEntity.setTakeId(IdUtil.createIdbyUUID());
        tbCfTakeCouponEntity.setCouponId(tbCfCoupon.getCouponId());
        tbCfTakeCouponEntity.setCreateTime(new Date());
        tbCfTakeCouponEntity.setUserId(userId);
        tbCfTakeCouponEntity.setEnableFlag(StateConstant.VALID);
        tbCfTakeCouponDao.save(tbCfTakeCouponEntity);
        //不需要更改原优惠券记录 不更改，因为会被覆盖，改为查询统计来获取已经领取的优惠券数量


    }
}
