package com.gic.haoban.manage.service.util;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.redisson.api.RAtomicLong;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.ServiceResponse;
import com.gic.commons.util.DateUtil;
import com.gic.enterprise.api.dto.EnterpriseDTO;
import com.gic.enterprise.api.service.EnterpriseService;
import com.gic.enterprise.service.CustomSettingApiService;
import com.gic.haoban.common.utils.DingUtils;
import com.gic.haoban.manage.service.errorcode.HaoBanErrCode;
import com.gic.haoban.manage.service.pojo.bo.QwLimitTimesBO;
import com.gic.redis.data.util.RedisUtil;

@Component
public class QwTimesUtils {

    private static Logger logger = LogManager.getLogger(QwTimesUtils.class);
    private static CustomSettingApiService customSettingApiService;

    public static EnterpriseService enterpriseService;

    @Autowired
    public void setCustomSettingApiService(CustomSettingApiService customSettingApiService) {
        QwTimesUtils.customSettingApiService = customSettingApiService;
    }

    @Autowired
    public void setEnterpriseService(EnterpriseService enterpriseService) {
        QwTimesUtils.enterpriseService = enterpriseService;
    }

    public static  Map<String,Object> getPendingTimes(String wxEnterpriseId) {
        QwInterfaceLimitEnum qwInterface = QwInterfaceLimitEnum.GET_PENDING_ID ;
        Date now = new Date();
        String dateStr = getDateStr(now);
        String interfaceName = qwInterface.getName();
        String keyMonth = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 6));
        Integer doneTimesMonth = RedisUtil.getCache(keyMonth, Integer.class);
        String keyDay = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 8));
        Integer doneTimesDay = RedisUtil.getCache(keyDay, Integer.class);
        String keyHour = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 10));
        Integer doneTimesHour = RedisUtil.getCache(keyHour, Integer.class);
        Map<String,Object> map = new HashMap<String, Object>() ;
        map.put("小时调用数", doneTimesHour) ;
        map.put("每天调用数", doneTimesDay) ;
        map.put("每月调用数", doneTimesMonth) ;
        QwLimitTimesBO setTimeBO = getSettingTimes(wxEnterpriseId, qwInterface);
        map.put("配置数", JSON.toJSON(setTimeBO)) ;
        return map ;
    }
    
    public static HaoBanErrCode isLimit(String wxEnterpriseId, String enterpriseId, QwInterfaceLimitEnum qwInterface) {
        QwLimitTimesBO setTimeBO = getSettingTimes(wxEnterpriseId, qwInterface);
        logger.info("获取配置次数={},wxEnterpriseId={},{}", JSON.toJSONString(setTimeBO), wxEnterpriseId,enterpriseId);
        // 先判断月
        String interfaceName = qwInterface.getName();
        Date now = new Date();
        String dateStr = getDateStr(now);
        String keyMonth = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 6));
        boolean monthResult = timesCheck(1, keyMonth, qwInterface, wxEnterpriseId, enterpriseId, now, setTimeBO);
        if (monthResult) {
            logger.info("月达到限制={},{}", keyMonth,enterpriseId);
            return HaoBanErrCode.ERR_2000;
        }
        // 天
        String keyDay = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 8));
        boolean dayResult = timesCheck(2, keyDay, qwInterface, wxEnterpriseId, enterpriseId, now, setTimeBO);
        if (dayResult) {
            logger.info("天达到限制={},{}", keyDay,enterpriseId);
            return HaoBanErrCode.ERR_2001;
        }
        // 小时
        String keyHour = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 10));
        boolean hourResult = timesCheck(3, keyHour, qwInterface, wxEnterpriseId, enterpriseId, now, setTimeBO);
        if (hourResult) {
            logger.info("小时达到限制={},{}", keyHour,enterpriseId);
            return HaoBanErrCode.ERR_2002;
        }
        return null;
    }

    private static boolean timesCheck(int type, String cacheKey, QwInterfaceLimitEnum qwInterface,
            String wxEnterpriseId, String enterpriseId, Date now, QwLimitTimesBO setTimeBO) {
        Integer doneTimes = RedisUtil.getCache(cacheKey, Integer.class);
        logger.info("type{}获取已调次数={},cacheKey={}", type, doneTimes == null ? 0 : doneTimes, cacheKey);
        if (null == doneTimes || doneTimes == 0) {
            return false;
        }
        int setTimes = 0;
        switch (type) {
        case 1:
            setTimes = setTimeBO.getMonth();
            break;
        case 2:
            setTimes = setTimeBO.getDay();
            break;
        case 3:
            setTimes = setTimeBO.getHour();
            break;
        default:
            break;
        }
        sendAlert(type, doneTimes, setTimes, qwInterface, enterpriseId, now);
        if (doneTimes >= setTimes) {
            return true;
        }
        return false;
    }

    private static QwLimitTimesBO getSettingTimes(String wxEnterpriseId, QwInterfaceLimitEnum qwInterface) {
        String key = String.format("%s_%s", qwInterface.getName(), wxEnterpriseId);
        QwLimitTimesBO times = getTimes(key);
        if (null == times) {
            return getTimes(qwInterface.getName());
        }
        return times;
    }

    private static QwLimitTimesBO getTimes(String key) {
        JSONObject searchParamMap = new JSONObject();
        searchParamMap.put("key", key);
        ServiceResponse<Map<String, Object>> resp = customSettingApiService.getDetail("tab_gic_map",
                searchParamMap.toJSONString());
        if (resp.isSuccess() && null != resp.getResult()) {
            return JSON.parseObject(resp.getResult().get("value").toString(), QwLimitTimesBO.class);
        }
        return null;
    }

    private static void sendAlert(int type, int doneTimes, int setTimes, QwInterfaceLimitEnum qwInterface,
            String enterpriseId, Date now) {
        // 调用次数达上线
        String time = null;
        String title = "已达上限";
        String alertKey = qwInterface.getName()+enterpriseId+"alert"+type ;
        boolean sendFlag = false;
        if (doneTimes >= setTimes) {
            sendFlag = true;
            if (type == 1) {
                time = DateUtil.dateToStr(now, "yyyy年MM月");
            }
            if (type == 2) {
                time = DateUtil.dateToStr(now, "yyyy年MM月dd日");
            }
            if (type == 3) {
                time = DateUtil.dateToStr(now, "yyyy年MM月dd日 HH:mm:ss");
            }
        } else if (type == 1 || type == 2) {
            switch (type) {
            case 1:
                setTimes = setTimes - 30000;
                break;
            case 2:
                setTimes = setTimes - 300000;
                break;
            default:
                break;
            }
            if (doneTimes >= setTimes) {
                sendFlag = true;
                if (type == 1) {
                    time = DateUtil.dateToStr(now, "yyyy年MM月");
                }
                if (type == 2) {
                    time = DateUtil.dateToStr(now, "yyyy年MM月dd日");
                }
                title = "即将达到可调用次数";
                alertKey+="_1" ;
            }
        }
        logger.info("告警key={},value={}",alertKey,RedisUtil.getCache(alertKey));
        if (sendFlag && null == RedisUtil.getCache(alertKey)) {
            if(type==3) {
                RedisUtil.setCache(alertKey, 1 , 60*59L);
            }else {
                RedisUtil.setCache(alertKey, 1 , 60*60*12L);
            }
            EnterpriseDTO enterpriseDTO = enterpriseService.getEnterpriseById(enterpriseId);
            String brandName = enterpriseDTO.getBrandName();
            // 达到上限时文案
            String msg = String.format("告警【%s】%s调用在【%s】%s", brandName, qwInterface.getRemark(), time, title);
            DingUtils.send(msg, false);
        }
    }

    public static void addTimes(String wxEnterpriseId, QwInterfaceLimitEnum obj) {
        String interfaceName = obj.getName();
        Date now = new Date();
        String dateStr = getDateStr(now);
        String keyHour = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 10));
        addTimes(3, keyHour);
        String keyDay = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 8));
        addTimes(2, keyDay);
        String keyMonth = getCacheKey(wxEnterpriseId, interfaceName, dateStr.substring(0, 6));
        addTimes(1, keyMonth);
    }

    private static String getCacheKey(String wxEnterpriseId, String interfacName, String dateStr) {
        return new StringBuilder(wxEnterpriseId).append(interfacName).append(dateStr).toString();
    }

    // 1月 2天 3小时
    private static void addTimes(int type, String key) {
        RAtomicLong cache = RedisUtil.getRedisClient().getAtomicLong(key);
        long val = cache.addAndGet(1);
        if (val <= 1) {
            switch (type) {
            case 1:
                cache.expire(31, TimeUnit.DAYS);
                break;
            case 2:
                cache.expire(1, TimeUnit.DAYS);
                break;
            case 3:
                cache.expire(1, TimeUnit.HOURS);
                break;
            default:
                break;
            }
        }
    }

    private static String getDateStr(Date now) {
        String dateStr = DateUtil.dateToStr(now, "yyyyMMddHHmmss");
        return dateStr;
    }
}
