package com.tax.file.service.impl;

import com.google.api.client.util.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.tax.file.constants.SqlConstants;
import com.tax.file.mapper.TkFileMapper;
import com.tax.file.model.*;
import com.tax.file.model.invoice.FileStatusModel;
import com.tax.file.service.api.TkFileSegmentService;
import com.tax.file.service.api.TkFileService;
import com.tax.file.utils.NationDic;
import com.tax.file.utils.NationUtil;
import com.yxcheng.token.common.cache.RedisService;
import com.yxcheng.token.common.service.AbstractService;
import com.yxcheng.token.constants.HttpRedisContants;
import com.yxcheng.token.utils.DateUtils;
import com.yxcheng.token.utils.MD5Util;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;


@Transactional
@Component
@ComponentScan(basePackages = {"com.tax.file"})
public class TkFileServiceImpl extends AbstractService<TkFileMapper,TkFileExample,TkFile> implements TkFileService {

    private static final Logger logger = LoggerFactory.getLogger(TkFileServiceImpl.class);

    @Autowired
    protected TkFileSegmentService tkFileSegmentService;
    @Autowired
    protected RedisService redisService;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int[] updateBatchJdbc(String sql, List<Object[]> batchArgs){
        int[] result = jdbcTemplate.batchUpdate(sql, batchArgs);
        return result;
    }

    @Override
    public String queryLastInvDate(TkTaxUser taxUser) {
        return baseMapper.queryLastInvDate(taxUser);
    }

    @Override
    public List<TkFile> queryPastData(TkTaxUser taxUser) {
        return baseMapper.queryPastData(taxUser);
    }

    public List<TkFile> queryApplyFileList(TkTaxUser taxUser) {
        List<TkFile> tkFileList = baseMapper.queryApplyFileList(taxUser);
        return tkFileList;
    }

    public List<TkFile> queryWaitDownFileList(TkTaxUser taxUser) {
        List<TkFile> tkFileList = baseMapper.queryWaitDownFileList(taxUser);
        return tkFileList;
    }

    public List<TkFile> queryResetFileList(TkTaxUser taxUser) {
        List<TkFile> tkFileList = baseMapper.queryResetFileList(taxUser);
        return tkFileList;
    }

    public List<TkFile> queryOverMonthFileList(TkTaxUser taxUser) {
        List<TkFile> tkFileList = baseMapper.queryOverMonthFileList(taxUser);
        return tkFileList;
    }

    public List<Map<String, Object>> countWaitDownFileList(TkTaxUser taxUser) {
        List<Map<String, Object>> countWaitDownFile = baseMapper.countWaitDownFileList(taxUser);
        return countWaitDownFile;
    }

    public List<Map<String, Object>> countWaitApplyFileList(TkTaxUser taxUser) {
        List<Map<String, Object>> countWaitApplyFile = baseMapper.countWaitApplyFileList(taxUser);
        return countWaitApplyFile;
    }


    @Override
    public List<TkFile> queryExitPastData(TkTaxUser taxUser) {
        return baseMapper.queryExitPastData(taxUser);
    }

    public Map<String, Map<String, TkFile>> queryWaitDownFileMap(TkTaxUser taxUser) {
        Map<String, Map<String, TkFile>> fileGroup = Maps.newConcurrentMap();
        Map<String, TkFile> subFileGroup = null;
        List<TkFile> fileList = queryWaitDownFileList(taxUser);
        for(TkFile tkFile:fileList) {
            String fileKey = tkFile.getFileGroupKey();
            if(fileGroup.containsKey(fileKey)) {
                subFileGroup = fileGroup.get(fileKey);
                subFileGroup.put(tkFile.getFileMd5(), tkFile);
            } else {
                subFileGroup = Maps.newConcurrentMap();
                subFileGroup.put(tkFile.getFileMd5(), tkFile);
                fileGroup.put(fileKey, subFileGroup);
            }
        }
        return fileGroup;
    }

    @Override
    public void updateApplyInfoByPrimaryKey(TkFile tkFile) {
        baseMapper.updateApplyInfoByPrimaryKey(tkFile);
    }

    @Override
    public void saveApplyFileList(String uuidFlag, TkTaxUser taxUser, Map<String, Date> applyDateMap) {
        for(String applyDateStart:applyDateMap.keySet()) {
            Date dateStart = DateUtils.str2Date(applyDateStart,  new SimpleDateFormat("yyyy-MM-dd"));
            Date dateEnd = applyDateMap.get(applyDateStart);

            //applyDateStart,applyDateEnd 存放字段串日期
            String applyDateEnd = DateUtils.date2Str(dateEnd,  new SimpleDateFormat("yyyy-MM-dd"));

            //获取此税号待申请发票类型列表
            String[] userInvTypes = NationDic.transferInvType(taxUser.getInvType(),taxUser.getSaleInvType(),taxUser.getInvSpec());
            String incomeInvType = userInvTypes[0];
            String saleInvType = userInvTypes[1];
            //申请下载-进项
            if (StringUtils.isNotBlank(incomeInvType)) {
                Arrays.asList(incomeInvType.split(NationDic.divideFlag)).stream().forEach(invType -> {
                    insertTkFile(taxUser, invType, NationDic.INVTYPE_INCOME, dateStart, dateEnd, applyDateStart, applyDateEnd);
                });
            }
            logger.info(uuidFlag + " saveApplyFileList invSpec : " + NationDic.INVTYPE_INCOME + ",invTypes:" + incomeInvType
                    + ",preDateStart:" + applyDateStart
                    + ",preDateEnd:" + applyDateEnd);
            //申请下载-销项
            if (StringUtils.isNotBlank(saleInvType)) {
                Arrays.asList(saleInvType.split(NationDic.divideFlag)).stream().forEach(invType -> {
                    insertTkFile(taxUser, invType, NationDic.INVTYPE_SALE, dateStart, dateEnd, applyDateStart, applyDateEnd);
                });
            }
            logger.info(uuidFlag + " saveApplyFileList invSpec : " + NationDic.INVTYPE_SALE + ",invTypes:" + saleInvType
                    + ",preDateStart:" + applyDateStart
                    + ",preDateEnd:" + applyDateEnd);
        }
    }

    private void insertTkFile(TkTaxUser taxUser, String invType, String invSpecie, Date dateStart, Date dateEnd, String applyDateStart, String applyDateEnd) {
        TkFileExample tkFileExample = new TkFileExample();
        tkFileExample.createCriteria()
                .andUserNameEqualTo(taxUser.getUserName())
                .andTaxnoEqualTo(taxUser.getTaxno())
                .andInvSpecEqualTo(invSpecie)
                .andInvTypeEqualTo(invType)
                .andInvDateStartEqualTo(dateStart)
                .andInvDateEndEqualTo(dateEnd);
        int tkFileListCount = baseMapper.countByExample(tkFileExample);
        if(tkFileListCount==0){
            TkFile tkFile = createTkFile(taxUser, invType, invSpecie, dateStart, dateEnd, applyDateStart, applyDateEnd);
            baseMapper.insertSelective(tkFile);
        }
    }

    private TkFile createTkFile(TkTaxUser taxUser, String invType, String invSpecie, Date dateStart, Date dateEnd, String applyDateStart, String applyDateEnd) {
        Date curDate = DateUtils.getDate();
        TkFile entity = new TkFile();
        entity.setApplyStatus(NationDic.APPLY_STATUS_NO);
        entity.setInvType(invType);
        entity.setTaxno(taxUser.getTaxno());
        entity.setInvSpec(invSpecie);
        entity.setInvDateStart(dateStart);
        entity.setInvDateEnd(dateEnd);
        entity.setInvDateStartStr(applyDateStart);
        entity.setInvDateEndStr(applyDateEnd);
        entity.setDecPwd(NationUtil.defaultPwd);
        entity.setUserName(taxUser.getUserName());
        entity.setZoneCode(taxUser.getZoneCode());
        entity.setCreateDate(curDate);
        entity.setUpdateDate(curDate);
        String beMonth = DateUtils.getMonth(dateEnd);
        entity.setFileMonth(beMonth);
        entity.setFileNum(0);
        //判断是否整月
        int daysOfMonth = DateUtils.getDaysOfMonth(dateEnd);
        long days = DateUtils.getDaySub(dateStart, dateEnd) + 1;
        if(daysOfMonth == days) {
            entity.setFileDataType("1");
        } else {
            entity.setFileDataType("0");
        }
        entity.setFileMd5(MD5Util.MD5Encode(taxUser.getTaxno() + invSpecie + invType + applyDateStart + applyDateEnd));
        return entity;
    }

    public void saveErrorFileInfo(TkFile tkFile, String errorType) {
        tkFile.setDownStatus("2");
        if(errorType.equals("1")) {
            tkFile.setErrorCode(DownFileInfoModel.DOWNLOAD_TIMES_OVER);
            tkFile.setFileName(DownFileInfoModel.DOWNLOAD_TIMES_OVER_CN);
        } else if(errorType.equals("2")) {
            tkFile.setErrorCode(DownFileInfoModel.RUNNING);
            tkFile.setFileName(DownFileInfoModel.RUNNING_CN);
        }
        tkFile.setUpdateDate(DateUtils.getDate());
        updateByPrimaryKey(tkFile);
    }

    public void updateApplyFileList(List<TkFile> applyFileList) {
        List<Object[]> invArrList = Lists.newArrayList();
        for(TkFile entity:applyFileList) {
            Object[] valueArr = new Object[6];
            valueArr[0] = entity.getApplyStatus();
            valueArr[1] = entity.getDownStatus();
            valueArr[2] = entity.getOldApplyDate();
            valueArr[3] = entity.getResetDate();
            valueArr[4] = entity.getDownCount();
            valueArr[5] = entity.getId();
            invArrList.add(valueArr);
        }
        updateBatchJdbc(SqlConstants.BATCH_UPDATE_RESET_FILE_SQL, invArrList);
    }

    public void deleteFileInfo(TkFile tkFile) {
        deleteByPrimaryKey(tkFile.getId());
        if(tkFile.getFileNum() > 1) {
            List<TkFileSegment> fileSegmentList = tkFileSegmentService.queryFileSegList(tkFile);
            for(TkFileSegment fileSegment:fileSegmentList) {
                tkFileSegmentService.deleteByPrimaryKey(fileSegment.getId());
            }
        }
    }


    public FileStatusModel getFileStatusModel(String timeFlag, TkTaxUser taxUser) {

        String userName = taxUser.getUserName();
        String taxno = taxUser.getTaxno();

        FileStatusModel fileStatusModel = new FileStatusModel();
        List<Map<String, Object>> tkFileCountList = countWaitApplyFileList(taxUser);

        Set applyStatusSet = Sets.newConcurrentHashSet();
        Set downStatusSet = Sets.newConcurrentHashSet();

        //用于计算需要导出的数量
        int downNum = 0;
        //用于计算需要下载的数量
        int initDownNum = 0;
        for(Map<String, Object> tkFileCountMap:tkFileCountList) {
            String responseStatus = (String)tkFileCountMap.get("response_status");
            if(responseStatus.equals(NationDic.RESPONSE_STATUS_NO)) {
                downNum += (long)tkFileCountMap.get("apply_num");
            } else {
                applyStatusSet.add(tkFileCountMap.get("apply_status"));
                downStatusSet.add(tkFileCountMap.get("down_status"));
                initDownNum += (long)tkFileCountMap.get("apply_num");
            }
        }
        if(taxUser.getInit().equals("1")) {
            if(initDownNum == 0) {
                //需要下载数量为0时，按处理完成归类
                fileStatusModel.setApplyStatus("2");
                fileStatusModel.setDownStatus("2");
            } else {
                fileStatusModel.setApplyStatus(getFileStatusCode(applyStatusSet));
                fileStatusModel.setDownStatus(getFileStatusCode(downStatusSet));
            }
        } else {
            //如果有初始数据，则还要执行
            fileStatusModel.setApplyStatus("1");
            fileStatusModel.setDownStatus("1");
        }
        fileStatusModel.setDownNum(downNum);
        if(downNum>0) {
            setExpNameList(userName, taxno, HttpRedisContants.COLLECT_LIST_TYPE_FILE);
            logger.info(timeFlag + " userName " + userName + ", taxno " + taxno + ",downNum:" + downNum);
        }
        return fileStatusModel;
    }

    private String getFileStatusCode(Set statusSet) {
        String applyStatus = "1";
        if(statusSet.contains("0")) {
            applyStatus = "1";
        } else {
            if(statusSet.contains("1") && statusSet.contains("2")) {
                applyStatus = "5";
            } else if(statusSet.contains("2")) {
                applyStatus = "5";
            } else {
                applyStatus = "2";
            }
        }
        return applyStatus;
    }

    private void setExpNameList(String userName, String taxno, String dataType) {
        String expName = HttpRedisContants.getInvoiceExpListGroupName(userName, taxno, dataType);
        redisService.set(expName, DateUtils.getDataString(DateUtils.yyyymmddhhmmss), 60 * 60 * 24 * 60);
    }

    public void updateApplyResetFileList(String uuidFlag, TkTaxUser taxUser, String overMonth) {
        String month = DateUtils.getPastMonth(overMonth, 2);
        String monthFirst = DateUtils.getMonthFirstByStr(month);
        taxUser.setMonthDate(monthFirst);
        List<TkFile> fileList = queryOverMonthFileList(taxUser);
        List<Object[]> invArrList = Lists.newArrayList();
        for(TkFile entity:fileList) {
            Object[] valueArr = new Object[2];
            valueArr[0] = "0";
            valueArr[1] = entity.getId();
            invArrList.add(valueArr);
        }
        if(invArrList.size()>0) {
            updateBatchJdbc(SqlConstants.BATCH_UPDATE_RUNNING_RESET_FILE_SQL, invArrList);
        }
        logger.info(uuidFlag + " taxno is " + taxUser.getTaxno() + " <<updateApplyResetFileList>> number is " + fileList.size());
    }
}
