package com.tax.file.service.async;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.tax.file.constants.CommonConstants;
import com.tax.file.mapper.FinInvoiceDetailMapper;
import com.tax.file.mapper.FinInvoiceMapper;
import com.tax.file.mapper.TkFileMapper;
import com.tax.file.model.FinInvoice;
import com.tax.file.model.FinInvoiceDetail;
import com.tax.file.model.TkFile;
import com.tax.file.model.TkFileExample;
import com.tax.file.service.api.FinInvoiceService;
import com.tax.file.utils.invoice.FileExcelReadUtil;
import com.yxcheng.token.utils.StringUtil;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author breeze
 * @date 2019-08-28
 * <p>
 * 读取文件入库
 */
@Component
public class ReadFileTask {
    private static final Logger logger = LoggerFactory.getLogger(ReadFileTask.class);
    private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
    
    @Autowired
    TkFileMapper tkFileMapper;
    @Autowired
    FinInvoiceService finInvoiceService;
    
    public void readFile() {
    	//1.查询待入库文件
        List<TkFile> tkFiles = tkFileMapper.excelQueryPage();//每次查出100条数据处理
    	
    	int size = (tkFiles == null?0:tkFiles.size());
    		
    	while(size > 0){
    		logger.info("ReadFileTask read file count is:"+size);
    		//2.读取文件入库
        	Iterator<TkFile> iter = tkFiles.iterator();
        	List<Future<String>> taskResults = new ArrayList<Future<String>>();
        	while(iter.hasNext()){
        		TkFile tkFile = iter.next();
        		taskResults.add(process(tkFile));
        	}
        	
        	 while (true) {
                 boolean isAllDone = true;
                 for (Future<String> taskResult : taskResults) {
                     isAllDone &= (taskResult.isDone() || taskResult.isCancelled());
                 }
                 if (isAllDone) {
                     // 任务都执行完毕，跳出循环
                     break;
                 }
             }
        	 
        	 
        	tkFiles = tkFileMapper.excelQueryPage();
         	
         	size = (tkFiles == null?0:tkFiles.size());
         	
         	logger.info("ReadFileTask read file count is:"+size);
         	
         	if(tkFiles == null || size == 0){
         		logger.info("ReadFileTask read file count is empty");
         		return;
         	}
    	}
    	
    }
    
    public Future<String> process(final TkFile tkFile) {
        return fixedThreadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                String flag = "0";
                readOneFile(tkFile);
                return flag;
            }
        });
    }
    
    /**
   	 * 读取单个URL入库
   	 *
   	 * @param tkFile
   	 * @return
   	 */
    public void readOneFile(TkFile tkFile){
    	logger.info("ReadFileTask readOneFile tkFile id:"+tkFile.getId());
    	ZipInputStream zipInputStream = null;
		InputStream inputStream = null;
		try {
			long startTime = System.currentTimeMillis();
			
			inputStream = FileExcelReadUtil.getInputStreamByUrl(tkFile.getUrl(), CommonConstants.timeout); //得到输入流
						
			zipInputStream = new ZipInputStream(inputStream);
			ZipEntry zipEntry = null;
			
			while ((zipEntry = zipInputStream.getNextEntry()) != null) {
				
				int re = zipInputStream.available();
				if(re == 0){
					logger.info("ReadFileTask readOneFile zipInputStream.available 1 tkFile id:"+tkFile.getId());
					continue;
				}
				
				//读取文件
			    Map<String, List> map = null;
				try {//解决单个EXCEL读取错误导致另外的EXCEL读取不了的问题
					InputStream inputStreamClone =  FileExcelReadUtil.inputStreamClone(zipInputStream);
					map = FileExcelReadUtil.readInvoiceExcel(inputStreamClone,tkFile.getInvType(),tkFile.getId());
				} catch (Exception e) {
					tkFile.setExcelImportCount(tkFile.getExcelImportCount()==null?0:tkFile.getExcelImportCount() + 2);
					logger.error("ReadFileTask readOneFile error2 tkFile id:"+tkFile.getId()+","+e);
					e.printStackTrace();
				}
			    
			    if(map == null){
			    	continue;
			    }
			    
			    //入库
			    finInvoiceService.insertInvoiceBatch(map,tkFile.getInvType());
			}
			
			long endTime = System.currentTimeMillis();
			
			logger.info("ReadFileTask readOneFile 耗时："+(endTime-startTime));
			
			tkFile.setExcelImport("1");
		} catch (Exception e) {
			logger.error(e.getMessage());
			logger.error("ReadFileTask readOneFile error tkFile id:"+tkFile.getId()+","+e);
			
			tkFile.setExcelImport("1");//设置只解析一次，如果有错误的手工处理
			tkFile.setExcelImportCount(tkFile.getExcelImportCount()==null?0:tkFile.getExcelImportCount() + 1);
			e.printStackTrace();
			if(e.getMessage().indexOf("Unexpected end of ZLIB input stream") >= 0){
				tkFile.setExcelImportCount(1);//重新解析一次
			}
			
			if(e.getMessage() != null && (e.getMessage().indexOf("MALFORMED") >= 0 || e.getMessage().indexOf("Invalid header signature") >= 0)){
				tkFile.setDownStatus("0");
			}
			
			e.printStackTrace();
		}finally{
			tkFileMapper.updateByPrimaryKeySelective(tkFile);
			if(zipInputStream != null){
				try {
					zipInputStream.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		    
    }
}
