package com.iformall.service.impl;

import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.domain.po.PushLimit;
import com.iformall.enums.EnumEnableType;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.PushLimitMapper;
import com.iformall.mapper.WxCouponActionLogMapper;
import com.iformall.service.PushLimitService;
import com.iformall.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PushLimitServiceImpl implements PushLimitService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private String keyPrev = "setting:pushlimit:";
    @Autowired
    PushLimitMapper pushLimitMapper;

    @Autowired
    WxCouponActionLogMapper wxCouponActionLogMapper;

    @Autowired
    @Qualifier("pushLimitRedisTemplate")
    private RedisTemplate<String, PushLimit> pushLimitRedisTemplate;

    @Override
    public PushLimit getPushLimit(String tenantId) {
        // get pushLime from cache
        String key = keyPrev + tenantId;

        // 缓存存在
        boolean hasKey = pushLimitRedisTemplate.hasKey(key);
        if (hasKey) {
            PushLimit pushLimit = pushLimitRedisTemplate.opsForValue().get(key);
            logger.info("PushLimitServiceImpl.getPushLimit() : 从缓存中获取了疲劳度 >> " + pushLimit.toString());
            return pushLimit;
        }

        PushLimit pushLimit = new PushLimit();
        pushLimit.setTenantId(tenantId);
        List<PushLimit> list = pushLimitMapper.findList(pushLimit);
        if (list.size() > 0) {
            pushLimit = list.get(0);
        } else {
            // 如果疲劳度设置不存在，启用默认值
            final IdWorker idWorker = IdWorker.get();
            pushLimit.setId(idWorker.nextId());
            pushLimit.setMsgAmount(3);
            pushLimit.setCouponAmount(10);
            pushLimit.setCouponDay(10);
            pushLimit.setTimeEnable(EnumEnableType.Enable.getCode());
            pushLimit.setTimeStart("8:00");
            pushLimit.setTimeEnd("23:00");
            pushLimit.setEnable(EnumEnableType.Enable.getCode());
            Date curDate = new Date();
            pushLimit.setCreateTime(curDate);
            pushLimit.setUpdateTime(curDate);
            pushLimitMapper.insert(pushLimit);
        }

        // 插入缓存
        pushLimitRedisTemplate.opsForValue().set(key, pushLimit);
        logger.info("PushLimitServiceImpl.getPushLimit() : 疲劳度插入缓存 >> " + pushLimit.toString());
        return pushLimit;
    }

    @Override
    public void saveOrUpdate(PushLimit record) {
        pushLimitMapper.updateById(record);

        // 缓存存在，删除缓存
        String key = keyPrev + record.getTenantId();
        boolean hasKey = pushLimitRedisTemplate.hasKey(key);
        if (hasKey) {
            pushLimitRedisTemplate.delete(key);
            logger.info("PushLimitServiceImpl.saveOrUpdate() : 从缓存中删除疲劳度 >> " + record.toString());
        }
    }

    @Override
    public boolean checkSendTime(String tenantId) {
        Date curDate = new Date();
        // 1. get tenant limit
        PushLimit pushLimit = getPushLimit(tenantId);
        // 1.1 疲劳度是否启用
        if(pushLimit.getEnable().equals(EnumEnableType.Disable.getCode())) {
            return true;
        }
        // 1.2 疲劳度时间是否启用
        if(pushLimit.getTimeEnable().equals(EnumEnableType.Enable.getCode())) {
            // 2. check time
            boolean isInDate = DateUtils.isInDate(curDate, pushLimit.getTimeStart(), pushLimit.getTimeEnd());
            if (!isInDate) {
                logger.error("不在疲劳度允许的时间段");
                throw new MallinkException(ErrorCode.PUSH_LIMIT_NOT_INRANG);
            }
            return isInDate;
        }

        return true;
    }

    @Override
    public boolean checkMsg(String tenantId) {
        Date curDate = new Date();
        // 1. get tenant limit
        PushLimit pushLimit = getPushLimit(tenantId);
        // 1.1 疲劳度是否启用
        if(pushLimit.getEnable().equals(EnumEnableType.Disable.getCode())) {
            return true;
        }
        // 2. check time
        // 2.1 疲劳度时间是否启用
        if(pushLimit.getTimeEnable().equals(EnumEnableType.Enable.getCode())) {
            boolean isInDate = DateUtils.isInDate(curDate, pushLimit.getTimeStart(), pushLimit.getTimeEnd());
            if (!isInDate) {
                logger.error("不在疲劳度允许的时间段");
                throw new MallinkException(ErrorCode.PUSH_LIMIT_NOT_INRANG);
            }
        }

        // TODO 3. check phone had up to limit
        return true;
    }

    @Override
    public boolean checkCoupon(String tenantId, Long cUserId, Long couponId) {
        Date curDate = new Date();
        // 1. get tenant limit
        PushLimit pushLimit = getPushLimit(tenantId);
        // 1.1 疲劳度是否启用
        if(pushLimit.getEnable().equals(EnumEnableType.Disable.getCode())) {
            return true;
        }
        // 2. check time 是否在给定的时间段内
        // 2.1 疲劳度时间是否启用
        if(pushLimit.getTimeEnable().equals(EnumEnableType.Enable.getCode())) {
            boolean isInDate = DateUtils.isInDate(curDate, pushLimit.getTimeStart(), pushLimit.getTimeEnd());
            if (!isInDate) {
                throw new MallinkException(ErrorCode.PUSH_LIMIT_NOT_INRANG);
            }
        }

        // 3. check 每人每天多少张券
        Map params = new HashMap<String, Object>();
        params.put("tenantId", tenantId);
        params.put("cUserId", cUserId);
        int countForUser = wxCouponActionLogMapper.getCountByUser(params);
        if (countForUser >= pushLimit.getCouponAmount()) {
            String errMsg = "每人每天领券已达到疲劳度上限: " + pushLimit.getCouponAmount();
            logger.error(errMsg);
            throw new MallinkException(ErrorCode.PUSH_LIMIT_UP_TO_1DAYLIMIT.getCode(), errMsg);
        }
        // 4. check 每人多少天内不会重复收到一张券
        if (pushLimit.getCouponDay() > 0) {
            params.put("couponId", couponId);
            params.put("dayNum", pushLimit.getCouponDay()-1);
            int countForUserCoupon = wxCouponActionLogMapper.getCountByUserAndCoupon(params);
            if (countForUserCoupon >= 1) {
                String errMsg = "每人" + pushLimit.getCouponDay() + "天领一张券已到疲劳度上限";
                logger.error(errMsg);
                throw new MallinkException(ErrorCode.PUSH_LIMIT_UP_TO_COUPONLIMIT.getCode(), errMsg);
            }
        }

        return true;
    }
}
