package com.tax.file.service.async.apply;


import com.google.common.collect.Maps;
import com.tax.file.model.TkTaxUser;
import com.tax.file.service.api.FileTokenService;
import com.tax.file.service.async.ExecuteMqService;
import com.tax.file.service.async.apply.util.ApplyUtil;
import com.yxcheng.token.common.cache.RedisService;
import com.yxcheng.token.common.model.MqMessage;
import com.yxcheng.token.constants.RedisContants;
import com.yxcheng.token.utils.DateUtils;
import com.yxcheng.token.utils.StringUtil;
import com.yxcheng.token.utils.UUIDGenerator;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

@Component
public class AsyncTkFileApplyService extends AbstractApplyService implements ExecuteMqService {
    private static final Logger logger = LoggerFactory.getLogger(AsyncTkFileApplyService.class);

    @Autowired
    private RedisService redisService;
    @Autowired
    private List<ApplyService> applyServices;
    @Autowired
    private FileTokenService fileTokenService;

    @Async("myExecutor")
    public Future<String> execute(MqMessage mqMessage){
        TkTaxUser taxUser = (TkTaxUser) mqMessage;

        String threadName = Thread.currentThread().getName();
        String uuidFlag = UUIDGenerator.generate();
        Date reqDate = DateUtils.getDate();
        String result = "请求成功";
        String userName = taxUser.getUserName();
        String taxno = taxUser.getTaxno();
        Instant start = Instant.now();
        logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is start." + " 线程名称： " + threadName);

        //如果税号运行中，直接返回，结束流程
        if(isExecuting(uuidFlag, userName, taxno)) {
            result = "运行中";
            logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The taxno is running.");
        } else {
            try{
                //超过次数不执行
                if(!timesLimitStrategy.isAccept(RedisContants.getLimitName(RedisContants.FILE_APPLY_TIMES_LOCK, userName, taxno))) {
                    result = "申请异常超过最大次数";
                    logger.info(uuidFlag + " applyDownFile " + " userName " + userName + " taxno "+taxno + " apply times is exceeding,it isn't run.");
                } else if(!timesLimitStrategy.isAccept(RedisContants.getLimitName(RedisContants.FILE_TOKEN_LOCK, userName, taxno), ApplyUtil.tokenTimes)) {
                    result = "token超过最大次数";
                    logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The token over times.");
                } else if(isOverMonth(userName, taxno)) {
                    result = "months超过最大次数";
                    logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The apply over two months.");
                } else {
                    Map<String,String> context = Maps.newConcurrentMap();
                    //记录请求token时间
                    String token = fileTokenService.getTokenCode(taxUser);
                    //如果token是空值或者token无效
                    if(StringUtils.isBlank(token) || !fileTokenService.checkToken(uuidFlag, taxUser, token)){
                        result = "token无效";
                        timesLimitStrategy.addTime(RedisContants.getLimitName(RedisContants.FILE_TOKEN_LOCK, userName, taxno),30*60,ApplyUtil.tokenTimes);
                        logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The taxno isn't get token.");
                    } else {
                        context.put(taxUser.getTaxno(),token);
                        for(ApplyService applyService : applyServices){
                            if(!applyService.apply(uuidFlag, taxUser, context)) {
                                result = applyService.getClass().getSimpleName() + " 运行失败";
                                logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The taxSystem is error." + result);
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                result = "运行异常" + StringUtil.getShortLog(e.getMessage(), 200);
                e.printStackTrace();
                timesLimitStrategy.addTime(RedisContants.getLimitName(RedisContants.FILE_APPLY_TIMES_LOCK, userName, taxno));
                logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is failure.The error is " + e.getMessage());
            } finally {
                //清除运行中状态
                finish(userName, taxno);
            }
        }
        //统计耗时
        printEndLog(uuidFlag, userName, taxUser.getTaxno(), start);
        fileLogService.saveLog(uuidFlag, taxUser.getUserName(), taxUser.getTaxno(), reqDate, taxUser.getTaxno(), "apply file " + result, new Date(), "0");
        return new AsyncResult<>("TkTaxUser="+taxUser.getTaxno()+" accomplished!");
    }


    public void printEndLog(String uuidFlag, String userName, String taxno, Instant start) {
        //统计耗时
        Instant end = Instant.now();
        long duration = end.toEpochMilli() - start.toEpochMilli();
        logger.info(uuidFlag + " userName " + userName + " taxno "+taxno + " apply download file is end.cost is {} ms!",duration);
    }

    public void finish(String userName, String taxno) {
        redisService.set(RedisContants.getLimitName(RedisContants.FILE_APPLY_LOCK, userName, taxno),"0",5);
    }

    public boolean isExecuting(String uuidFlag, String userName, String taxno) {
        boolean execFlag = false;
        try {
            if("1".equals(redisService.getKey(RedisContants.getLimitName(RedisContants.FILE_APPLY_LOCK, userName, taxno)))) {
                execFlag = true;
            } else {
                redisService.set(RedisContants.getLimitName(RedisContants.FILE_APPLY_LOCK, userName, taxno),"1",2*60*60);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(uuidFlag + " userName " + userName + " taxno "+taxno + " operation redis is error!" + e.getMessage());
            //redis连接不上认为是运行中
            execFlag = true;
        }
        return execFlag;
    }

    public boolean isOverMonth(String userName, String taxno) {
       return redisService.exists(RedisContants.getLimitName(RedisContants.FILE_APPLY_ALARM, userName, taxno));
    }


}
