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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.tax.file.constants.CommonConstants;
import com.tax.file.model.*;
import com.tax.file.service.api.*;
import com.tax.file.service.async.strategy.ExecuteTimesLimitStrategy;
import com.tax.file.utils.NationDic;
import com.tax.file.utils.NationUtil;
import com.yxcheng.token.common.cache.RedisService;
import com.yxcheng.token.constants.RedisContants;
import com.yxcheng.token.utils.DateUtils;
import com.yxcheng.token.utils.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class AbstractApplyService {
    protected   final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    protected TkTaxUserService tkTaxUserService;
    @Autowired
    protected ExecuteTimesLimitStrategy timesLimitStrategy;
    @Autowired
    protected TkFileService tkFileService;
    @Autowired
    private FileTokenService fileTokenService;
    @Autowired
    protected FileTaxLogService fileTaxLogService;
    @Autowired
    protected FileLogService fileLogService;
    @Autowired
    protected LackDateFileService lackDateFileService;
    @Autowired
    protected RedisService redisService;


    public String SUCCCESS = "0";
    public String FAIL = "-1";
    public String ThirtyDays = "1";
    public String PAST = "2";
    public String RepeatApply = "3";
    public String OverApply = "4";
    public String OverApply24 = "5";
    public String OverApplyCurMonth = "6";
    public String TokenOver = "9";



    protected boolean doRangeApplyFile(String uuidFlag, TkTaxUser user, Map<String,String> context,String invSpec, String invTypes, Date preDateStart, Date preDateEnd) {
        //建立申请文件实体
        TkFile entity = new TkFile();
        entity.setTaxno(user.getTaxno());
        entity.setInvSpec(invSpec);
        entity.setInvType(invTypes);
        entity.setDecPwd(NationUtil.defaultPwd);
        entity.setInvDateEnd(preDateEnd);
        entity.setInvDateStart(preDateStart);
        entity.setToken(context.get(user.getTaxno()));
        entity.setZoneCode(user.getZoneCode());

        //结束日期不能大于当前日期
        if(preDateEnd.after(DateUtils.getDate())){
            entity.setInvDateEnd(DateUtils.getDate());
        }

        boolean applyFlag = false;
        String resultIndex = fileDownApply(uuidFlag, user, context, entity).getApplyErrorCode();
        if(resultIndex.equals(SUCCCESS) || resultIndex.equals(OverApply24)) {
            Arrays.asList(invTypes.split(NationDic.divideFlag)).stream().forEach(invType -> {
                insertTkFile(user, invType, invSpec, preDateStart, preDateEnd);
            });
            applyFlag = true;
            context.put("result", "0");
        }else if(resultIndex == ThirtyDays){
            applyFlag = true;
        } else if(resultIndex == OverApply) {
            applyFlag = true;
            context.put("result", "4");
        } else if(resultIndex == OverApplyCurMonth){
            applyFlag = true;
        }
        logger.info(uuidFlag + " doRangeApplyFile result : " + applyFlag + ", invSpec : " + invSpec + ",invTypes:" + invTypes + ",resultIndex:" + resultIndex
            + ",preDateStart:" + DateUtils.date2Str(preDateStart, DateUtils.date_sdf)+ ",preDateEnd:" + DateUtils.date2Str(preDateEnd, DateUtils.date_sdf));
        return applyFlag;
    }

    protected ApplyFileModel fileDownApply(String uuidFlag, TkTaxUser user, Map<String,String> context, TkFile entity){
        boolean isFinish = false;
        String resultIndex = FAIL;
        String responseResult = "";
        Date reqDate = DateUtils.getDate();
        String dataStr = "error";
        try {
        	logger.info(uuidFlag + " fileDownApply taxno param:" + user.getTaxno() + ","
                    + DateUtils.date2Str(entity.getInvDateStart(), DateUtils.date_sdf)+","
                    + DateUtils.date2Str(entity.getInvDateEnd(), DateUtils.date_sdf));
        	//申请与局端交互
            String invDateStart = DateUtils.date2Str(entity.getInvDateStart(), DateUtils.date_sdf);
            String invDateEnd = DateUtils.date2Str(entity.getInvDateEnd(), DateUtils.date_sdf);

            dataStr = NationUtil.getFileDownApplyParams(entity, invDateStart, invDateEnd);

            JSONObject result = NationUtil.fileDownApply(uuidFlag, entity, invDateStart, invDateEnd, dataStr);

            logger.info(uuidFlag + " fileDownApply taxno:" + user.getTaxno() + " result:" + result);
            if(result!=null){
                String code = result.getString("key1");
                String message = result.getString("key2");
                if("01".equals(code)){
                    isFinish = true;
                    resultIndex = SUCCCESS;
                } else if("n4000001".equals(code)){
                    //申请过的
                    if(message.contains(CommonConstants.THIRTY_DAYS_MSG)) {
                        isFinish = true;
                        resultIndex = ThirtyDays;
                    } else if(message.contains(CommonConstants.OVER_APPLY_MSG)) {
                        isFinish = true;
                        resultIndex = OverApply;
                    } else if(message.contains(CommonConstants.OVER_APPLY_24_MSG) || message.contains(CommonConstants.OVER_APPLY_48_MSG)) {//24小时内不能重复申请
                        isFinish = true;
                        resultIndex = OverApply24;
                    } else if(message.contains(CommonConstants.OVER_APPLY_CURRENT_MONTH_MSG)) {//达到允许上限
                        isFinish = true;
                        resultIndex = OverApplyCurMonth;
                    } else{
                        //库里已经存在这些数据
                        if(isExistAndNationAlreadyGet(user, context, entity)){
                            isFinish = true;
                            resultIndex = RepeatApply;
                        }
                    }
                } else if("w4000000".equals(code)) {
                    fileTokenService.noticeGetNewToken(uuidFlag, user);
                }

                if(isFinish){
//                    saveLackDateFile(user, entity, message, resultIndex);
                } else {
                    timesLimitStrategy.addTime(RedisContants.FILE_APPLY_TIMES_LOCK + user.getTaxno());
                }
                responseResult = JSON.toJSONString(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
            responseResult = StringUtil.getShortLog(e.getMessage(), 500);
            timesLimitStrategy.addTime(RedisContants.FILE_APPLY_TIMES_LOCK + user.getTaxno());
            logger.error(uuidFlag + " fileDownApply taxno:" + user.getTaxno() + " is error:" + e.getMessage());
        }
        fileTaxLogService.saveLog(uuidFlag, user.getTaxno(), reqDate,
                JSON.toJSONString(entity, SerializerFeature.WriteDateUseDateFormat), responseResult, DateUtils.getDate(),"1", entity, resultIndex);
        logger.info(uuidFlag + " fileDownApply taxno:" + user.getTaxno() + " resultIndex:" + resultIndex);
        return new ApplyFileModel(isFinish, resultIndex);
    }

    protected void insertLackDateFile(TkFile entity) {

        LackDateFileExample example = new LackDateFileExample();
        example.createCriteria().andTaxnoEqualTo(entity.getTaxno())
                .andInvDateStartEqualTo(entity.getInvDateStart())
                .andInvDateEndEqualTo(entity.getInvDateEnd())
                .andInvSpecEqualTo(entity.getInvSpec());
        LackDateFile origin = lackDateFileService.getOne(example);

        Date curDate = DateUtils.getDate();
        if(origin==null){
            LackDateFile lackDateFile = new LackDateFile();
            lackDateFile.setTaxno(entity.getTaxno());
            lackDateFile.setInvDateStart(entity.getInvDateStart());
            lackDateFile.setInvDateEnd(entity.getInvDateEnd());
            lackDateFile.setCreateDate(curDate);
            lackDateFile.setApplyStatus("0");
            lackDateFile.setInvSpec(entity.getInvSpec());
            lackDateFile.setUpdateDate(curDate);
            lackDateFile.setApplyFlag("0");
            lackDateFile.setInvMonth(DateUtils.getMonth(entity.getInvDateStart()));
            lackDateFileService.insertSelective(lackDateFile);
        }else{
            origin.setApplyStatus("0");
            origin.setApplyFlag("0");
            origin.setApplyDate(null);
            origin.setUpdateDate(curDate);
            lackDateFileService.updateByPrimaryKeySelective(origin);
        }
    }

    private boolean isExistAndNationAlreadyGet(TkTaxUser taxUser, Map<String, String> context, TkFile entity) {
        String invType = taxUser.getInvType();
        if(entity.getInvSpec().equals("2")) {
            invType = taxUser.getSaleInvType();
        }
        List<String> invTypeList = Arrays.asList(invType.split("="));
        TkFileExample tkFileExample = new TkFileExample();
        tkFileExample.createCriteria()
                .andTaxnoEqualTo(taxUser.getTaxno())
                .andUserNameEqualTo(taxUser.getUserName())
                .andInvSpecEqualTo(entity.getInvSpec())
                .andInvTypeIn(invTypeList)
                .andApplyStatusEqualTo("1")
                .andInvDateStartEqualTo(DateUtils.toDate(entity.getInvDateStart(),"yyyy-MM-dd"))
                .andInvDateEndEqualTo(DateUtils.toDate(entity.getInvDateEnd(),"yyyy-MM-dd"));
        int count = tkFileService.countByExample(tkFileExample);
        return count == invTypeList.size();
    }

    private TkFile assembleTkFile(TkTaxUser user, String invType, String invSpecie, String pwd, Date preDateStart, Date preDateEnd) {
        TkFile entity = new TkFile();
        entity.setApplyStatus("1");
        entity.setInvType(invType);
        entity.setTaxno(user.getTaxno());
        entity.setInvSpec(invSpecie);
        entity.setInvDateStart(preDateStart);
        entity.setInvDateEnd(preDateEnd);
        entity.setDecPwd(pwd);
        entity.setUserName(user.getUserName());
        entity.setZoneCode(user.getZoneCode());
        Date curDate = DateUtils.getDate();
        entity.setCreateDate(curDate);
        entity.setUpdateDate(curDate);
        return entity;
    }


    private void insertTkFile(TkTaxUser user, String invType, String spec, Date preDateStart, Date preDateEnd) {
        TkFileExample tkFileExample = new TkFileExample();
        tkFileExample.createCriteria()
                .andTaxnoEqualTo(user.getTaxno())
                .andUserNameEqualTo(user.getUserName())
                .andInvSpecEqualTo(spec)
                .andInvTypeEqualTo(invType)
                .andApplyStatusEqualTo("1")
                .andInvDateStartEqualTo(DateUtils.toDate(preDateStart,"yyyy-MM-dd"))
                .andInvDateEndEqualTo(DateUtils.toDate(preDateEnd,"yyyy-MM-dd"));
        List<TkFile> readyFile = tkFileService.selectByExample(tkFileExample);
        if(readyFile==null || readyFile.size()==0){
            TkFile incomeTkFile = assembleTkFile(user, invType, spec, NationUtil.defaultPwd, preDateStart, preDateEnd);
            tkFileService.insertSelective(incomeTkFile);
        }
    }


    protected boolean doApply(String uuidFlag, TkTaxUser taxUser,  Map<String,String> context, Date dateStart, Date dateEnd){
        //获取此税号待申请发票类型列表
        String[] userInvTypes = NationDic.transferInvType(taxUser.getInvType(),taxUser.getSaleInvType(),taxUser.getInvSpec());
        String incomeInvType = userInvTypes[0];
        String saleInvType = userInvTypes[1];
        //申请下载-进项
        if (StringUtils.isNotBlank(incomeInvType) && !doRangeApplyFile(uuidFlag, taxUser, context, NationDic.INVTYPE_INCOME, incomeInvType, dateStart, dateEnd)) {
            return false;
        }
        //设置申请延时
        reduceFrequency(taxUser);
        //申请下载-销项
        if (StringUtils.isNotBlank(saleInvType) && !doRangeApplyFile(uuidFlag, taxUser, context, NationDic.INVTYPE_SALE, saleInvType, dateStart, dateEnd)) {
            return false;
        }
        //设置申请延时
        reduceFrequency(taxUser);
        return true;
    }


    protected boolean doApply(String uuidFlag, TkTaxUser taxUser,  Map<String,String> context, Date dateStart, Date dateEnd,String invSpec){
        String[] userInvTypes = NationDic.transferInvType(taxUser.getInvType(), taxUser.getSaleInvType(),taxUser.getInvSpec());
        String incomeInvType = userInvTypes[0];
        String saleInvType = userInvTypes[1];

        if("1".equals(invSpec) && StringUtils.isNotBlank(incomeInvType) && !doRangeApplyFile(uuidFlag, taxUser,context,"1",incomeInvType,dateStart,dateEnd)){
            return false;
        }
        reduceFrequency(taxUser);
        if("2".equals(invSpec) && StringUtils.isNotBlank(saleInvType) && !doRangeApplyFile(uuidFlag, taxUser,context,"2",saleInvType,dateStart,dateEnd)){
            return false;
        }
        reduceFrequency(taxUser);
        return true;
    }

    private void reduceFrequency(TkTaxUser taxUser){
        try {
            if ("3302".equals(taxUser.getZoneCode())) {
                TimeUnit.SECONDS.sleep(2);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        String applyMessage = "增值税专用发票进项票开票（填发）为2020年10月已经与2021年06月17日提交申请，30天内不能重复申请";
        String applyDateStr = null;
        if(StringUtil.isNotEmpty(applyMessage) && applyMessage.contains("年") && applyMessage.contains("月") && applyMessage.contains("日")) {
            applyDateStr = applyMessage.substring(applyMessage.indexOf("已经与") + 3, applyMessage.indexOf("提交申请"));
        }
        TkFile file = new TkFile();
        System.out.println(JSON.toJSONString(file, SerializerFeature.WriteDateUseDateFormat));
    }

}
