package com.dxhy.core.thread;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
//import com.alibaba.excel.metadata.Sheet;
//import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dxhy.common.service.impl.TabulateRedisServiceImpl;
import com.dxhy.common.util.CellWriteHandler;
import com.dxhy.common.util.CustomCellWriteHandler;
import com.dxhy.common.util.ExceptionUtil;
import com.dxhy.common.util.StringHelper;
import com.dxhy.common.utils.DateUtils;
import com.dxhy.core.entity.TDxExcelExportlog;
import com.dxhy.core.feign.IFeginWebsocket;
import com.dxhy.core.rabbitmq.Sender;
import com.dxhy.core.service.export.PoolPaperService;
import com.dxhy.core.service.singletable.IExcelExportlogService;
import com.dxhy.core.util.JsonResponseUtils;
import com.dxhy.oss.service.FileService;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

/**
 * @author user
 */
@Slf4j
@SuppressWarnings({"AliDeprecation", "AlibabaUndefineMagicConstant", "AlibabaMethodTooLong"})
public class PoolAddTaxThread extends BaseThread {

    /**
     * 默认要导出第几页的数据
     */
    private final int default_curr = 1;
    /**
     * 默认每页导出多少条数据
     */
    private final int default_size = 5000;
    /**
     * 文件名前缀
     */
    private final String fileNamePrefix = "增值税发票采集";
    /**
     * 文件名后缀
     */
    private final String fileNameSurfix = ".xls";
    /**
     * 文件名中间分隔符
     */
    private final String fileSplit = "_";
    /**
     * excel的标题
     */
    private String title = "增值税发票采集";
    /**
     * 导出excel的列名
     */
    private final String[] titleColumns = {"序号", "发票类型", "发票代码", "发票号码", "发票状态", "开票日期", "销方名称", "销方税号", "金额", "税额",
            "有效税额", "价税合计", "认证状态", "认证类型", "认证日期", "认证方式", "认证人", "采集状态", "底账库采集时间", "采集来源", "签收方式", "签收状态", "签收日期", "签收人",
        "入账月份", "是否末次摊销", "摊销金额", "剩余金额", "业务单号", "入池时间","凭证号","过账时间","账期","影像号","报账单号","报账人","入账状态","所属组织"};

    /**
     * 导出excel的列名
     */
    private final String[] detailTitleColumns =
            {"序号", "发票代码", "发票号码", "货物或应税劳务名称", "规格型号", "单位", "数量", "单价", "金额", "税额", "税率", "车牌号", "类型", "通行日期起", "通行日期止"};

    //    private Sheet sheet;
//    private Table table;
    private WriteSheet writeSheet;
    private WriteTable writeTable;
    private ExcelWriter writer = null;

    private final IExcelExportlogService exportLogService;

    private final List<TDxExcelExportlog> exportLogs;

    private final PoolPaperService poolPaperService;

    private final FileService fileService;

    private final Sender sender;

    private final IFeginWebsocket feginWebsocket;
    private final TabulateRedisServiceImpl tabulateRedisService;

    public PoolAddTaxThread(IExcelExportlogService exportLogService, List<TDxExcelExportlog> exportLogs,
                            PoolPaperService poolPaperService, FileService fileService, Sender sender, IFeginWebsocket feginWebsocket,
                            TabulateRedisServiceImpl tabulateRedisService) {
        this.exportLogService = exportLogService;
        this.exportLogs = exportLogs;
        this.poolPaperService = poolPaperService;
        this.fileService = fileService;
        this.sender = sender;
        this.feginWebsocket = feginWebsocket;
        this.tabulateRedisService = tabulateRedisService;
    }

    @Override
    public void run() {
        for (TDxExcelExportlog exportLog : exportLogs) {
            // 日志表主键
            Long id = exportLog.getId();
            String userid = exportLog.getUserAccount();
            String userName = exportLog.getUserName();
            // 导出条件
            String condition = exportLog.getConditions();
            // 数据源名称
            String dbName = exportLog.getDbName();
            if (StringHelper.isBlank(dbName)) {
                dbName = "";
            }
            String createDate = DateUtils.dateToStrLong(exportLog.getCreateDate());

            JSONObject msg = new JSONObject();

            // 捕获异常，防止某一条日志导出出错，影响其它日志的导出
            try {
                exportLogService.updateStart(id, dbName);

                // 应该保存的参数
                JSONObject prams = JSONObject.parseObject(condition);
                String keyWord = prams.getString("keyWord");
                String gfsh = prams.getString("gfsh");
                String fpzt = prams.getString("invoiceStatus");
                String invoiceType = prams.getString("invoiceType");
                String qszt = prams.getString("qszt");
                String qsr = prams.getString("qsr");
                String qsfs = prams.getString("qsfs");
                String rzzt = prams.getString("rzzt");
                String rzlx = prams.getString("rzlx");
                String rzr = prams.getString("rzr");
                String cjksyf = prams.getString("cjksyf");
                String cjjsyf = prams.getString("cjjsyf");
                String gfTaxNo = prams.getString("gfTaxNo");
                String inAccountStatus = prams.getString("inAccountStatus");
                String inAccountMonth = prams.getString("inAccountMonth");
                String company = prams.getString("company");
                String bzdh = prams.getString("bzdh");
                String bzr = prams.getString("bzr");
                String companyCode = prams.getString("companyCode");
                JSONArray companyCodeArray = prams.getJSONArray("companyCodes");
                String snVoucherNumber = prams.getString("snVoucherNumber");
                String accountPeriod = prams.getString("accountPeriod");
                if (StringUtils.isNotEmpty(accountPeriod) && accountPeriod.length() > 7){
                    accountPeriod  = accountPeriod.substring(0,7);
                }
                String imageNumber = prams.getString("imageNumber");
                String postingTimeEnd = prams.getString("postingTimeEnd");
                String postingTimeStart = prams.getString("postingTimeStart");

                List<String> companyCodes = companyCodeArray.toJavaList(String.class);
                // 参数转换为需要的形式
                Map<String, Object> pramsMap = new HashMap<>(16);
                pramsMap.put("dbName", dbName);
                pramsMap.put("bzdh",bzdh);
                pramsMap.put("bzr",bzr);
                pramsMap.put("inAccountStatus",inAccountStatus);
                pramsMap.put("snVoucherNumber",snVoucherNumber);
                pramsMap.put("accountPeriod",accountPeriod);
                pramsMap.put("imageNumber",imageNumber);
                pramsMap.put("postingTimeEnd",postingTimeEnd);
                pramsMap.put("postingTimeStart",postingTimeStart);

                List<String> gfshList = new ArrayList<>();
                if (!StringHelper.isBlank(gfsh)) {
                    gfshList = StringHelper.stringToList(gfsh);
                    pramsMap.put("gfsh", gfshList);
                } else {
                    pramsMap.put("gfsh", gfshList);
                }
                boolean flag = checkList(gfshList);
                if (flag){
                    pramsMap.put("sign","88");
                    log.info("登陆账号无税号");
                }

                if (cjksyf != null && !"".equals(cjksyf)) {
                    pramsMap.put("cjksyf", DateUtils.getMorning(DateUtils.strToDate(cjksyf)));
                }
                if (cjjsyf != null && !"".equals(cjjsyf)) {
                    pramsMap.put("cjjsyf", DateUtils.getNight(DateUtils.strToDate(cjjsyf)));
                }
                if (prams.get("kpksrq") != null && !"".equals(prams.get("kpksrq"))) {
                    pramsMap.put("kpksrq",
                            DateUtils.getMorning(DateUtils.strToDate(prams.get("kpksrq").toString())));
                }
                if (prams.get("kpjsrq") != null && !"".equals(prams.get("kpjsrq"))) {
                    pramsMap.put("kpjsrq", DateUtils.getNight(DateUtils.strToDate(prams.get("kpjsrq").toString())));
                }
                if (prams.get("skssq") != null && !"".equals(prams.get("skssq")) && "1".equals(prams.get("rzzt"))) {
                    pramsMap.put("skssq", prams.get("skssq").toString().replace("-", ""));
                } else {
                    pramsMap.put("skssq", "");
                }
                if (prams.get("qsyf") == null && "".equals(prams.get("qsyf")) && !"1".equals(prams.get("qszt"))) {
                    pramsMap.put("qsyf", "");
                }else {
                    pramsMap.put("qsyf", prams.get("qsyf"));
                }
                if (prams.get("inAccountMonth") == null && "".equals(prams.get("inAccountMonth"))
                        && !"1".equals(prams.get("inAccountStatus"))) {
                    pramsMap.put("inAccountMonth", "");
                }else {
                    pramsMap.put("inAccountMonth", inAccountMonth);
                }
                pramsMap.put("keyWord", keyWord);
                pramsMap.put("qszt", qszt);
                pramsMap.put("invoiceType", invoiceType);
                pramsMap.put("qsr", qsr);
                pramsMap.put("qsfs", qsfs);
                pramsMap.put("fpzt", fpzt);
                pramsMap.put("rzzt", rzzt);
                pramsMap.put("rzlx", rzlx);
                pramsMap.put("rzr", rzr);
                pramsMap.put("inAccountStatus", inAccountStatus);
                pramsMap.put("company", company);
                pramsMap.put("invoiceSource",prams.getString("invoiceSource"));
                pramsMap.put("companyCodes",companyCodes);
                pramsMap.put("companyCode",companyCode);
                // 导出文件名
                StringBuilder ftpFileName = new StringBuilder();
                ftpFileName.append(userid);
                ftpFileName.append(fileSplit);
                ftpFileName.append(fileNamePrefix);
                ftpFileName.append(fileSplit);
                ftpFileName.append(DateUtils.getStringDateShort());
                ftpFileName.append(fileSplit);
                ftpFileName.append((new Date()).getTime());
                ftpFileName.append(fileNameSurfix);
//                ftpFileName.append(fileNamePrefix);
//                ftpFileName.append(DateUtils.dateToMonthStr(new Date()));
//                ftpFileName.append(fileSplit);
//                if ("99".equals(gfTaxNo)) {
//                    if (gfshList.size() > 0) {
//                        if (StringUtils.isNotEmpty(gfshList.get(0))){
//                            ftpFileName.append(poolPaperService.getblocName(gfshList.get(0)));
//                            ftpFileName.append(fileSplit);
//                        }
//                    }
//                } else {
//                    if (gfshList.size() > 0) {
////                        for (String s : gfshList) {
////                            if (StringUtils.isNotEmpty(s)){
////                                ftpFileName.append(poolPaperService.getGfName(s));
////                                ftpFileName.append(fileSplit);
////                            }
////                        }
//                        if (StringUtils.isNotEmpty(gfshList.get(0))){
//                            ftpFileName.append(poolPaperService.getGfName(gfshList.get(0)));
//                            ftpFileName.append(fileSplit);
//                        }
//                    }
//                }
//
//                ftpFileName.append(DateUtils.getNowTimeStamp());
//                title = ftpFileName.toString();
//                ftpFileName.append(fileNameSurfix);

                // 本地文件存储路径
                StringBuilder excelFile = new StringBuilder();
                excelFile.append(fileService.getLocalPathDefault());
                excelFile.append(ftpFileName.toString());
                File filePath = new File(getFilePath(excelFile.toString()));
                if (!filePath.exists()) {
                    filePath.mkdirs();
                }

                File file = new File(excelFile.toString());
                if (!file.exists()) {
                    file.delete();
                }

                if (!file.exists()) {
                    file.createNewFile();
                }
                OutputStream out = new FileOutputStream(excelFile.toString());
//                writer = new ExcelWriter(null, out, ExcelTypeEnum.XLSX, true, new CellWriteHandler());
                ExcelWriterBuilder builder = EasyExcel.write(excelFile.toString());
                builder.registerWriteHandler(new CustomCellWriteHandler());
                writer = builder.build();
                // 递归导出数据到excel 发票信息
                this.cicleExport(pramsMap, default_curr, excelFile.toString(), out, writer);

                this.detailCicleExport(pramsMap, default_curr, excelFile.toString(), out, writer);
                writer.finish();
                // FTP文件存储路径
                String[] toDay = DateUtil.today().split("-");
                String ftpFilePath = fileService.getPathPrefix() + userName + "/" + "excelFile/" + toDay[0] + "/"
                        + toDay[1] + "/" + toDay[2] + "/" + ftpFileName.toString();
                // 文件上传ftp
                fileService.uploadFile(ftpFilePath, excelFile.toString());

                // 设置成功消息内容
                msg.put("title", super.getSuccTitle(title));
                msg.put("content", super.getSuccContent(createDate));
                msg.put("url", super.getUrl(id));
                msg.put("useraccount", userName);

                // 记录导出完成状态
                exportLogService.updateSucc(id, ftpFilePath, dbName);

            } catch (Exception e) {
                String errmsg = ExceptionUtil.getExceptionDeteil(e, 4000);
                // 设置失败消息内容
                msg.put("title", super.getFailTitle(title));
                msg.put("content", super.getFailContent(createDate, errmsg));
                msg.put("url", "");
                msg.put("useraccount", userName);

                log.error("", e);
                // 记录导出出错状态
                exportLogService.updateFail(id, errmsg, dbName);
            } finally {
                // 发送导出消息到mq
                String responseResult = JsonResponseUtils.responseResult(msg);
                sender.sendToMsg(responseResult);

                // 申请成功后像websocket发送申请信息
                feginWebsocket.setMessageToWebsocket(userName);
            }
        }
    }

    /**
     * 递归导出数据到excel文件，防止jvm oom
     *
     * @param pramsMap
     *            查询数据参数集合
     * @param curr
     *            当前第几页
     * @param excelFile
     *            导出的文件
     * @param writer
     * @throws Exception
     *
     */

    private boolean cicleExport(Map<String, Object> pramsMap, int curr, String excelFile, OutputStream out,
                                ExcelWriter writer) throws Exception {
        // 查询指定页数的数据
        JSONObject pageData = poolPaperService.listAddTaxInvoice(pramsMap, curr, default_size);
        boolean hasNext = pageData.getBooleanValue("hasNext");
        List<String[]> dataList = (List<String[]>)pageData.get("datalist");
        boolean firstPage = false;
        if (curr == default_curr) {
            firstPage = true;
        }

        // 数据不是最后一页
        if (hasNext) {
            int nextPage = pageData.getIntValue("nextPage");
            // 写入当前页数据
            exportListArrayToExcel(excelFile, title, titleColumns, dataList, firstPage, false, 1, "增值税发票", out, writer);
            // 更新页数
            return cicleExport(pramsMap, nextPage, excelFile, out, writer);
        } else {
            // 写入最后一页数据
            exportListArrayToExcel(excelFile, title, titleColumns, dataList, firstPage, true, 1, "增值税发票", out, writer);
            return hasNext;
        }

    }

    /**
     * 递归导出数据到excel文件，防止jvm oom
     *
     * @param pramsMap
     *            查询数据参数集合
     * @param curr
     *            当前第几页
     * @param excelFile
     *            导出的文件
     * @param writer
     * @throws Exception
     *
     */

    private boolean detailCicleExport(Map<String, Object> pramsMap, int curr, String excelFile, OutputStream out,
                                      ExcelWriter writer) throws Exception {
        // 查询指定页数的数据
        JSONObject pageData = poolPaperService.listAddTaxInvoiceDetail(pramsMap, curr, default_size);
        boolean hasNext = pageData.getBooleanValue("hasNext");
        List<String[]> dataList = (List<String[]>)pageData.get("datalist");
        boolean firstPage = false;
        if (curr == default_curr) {
            firstPage = true;
        }

        // 数据不是最后一页
        if (hasNext) {
            int nextPage = pageData.getIntValue("nextPage");
            // 写入当前页数据
            exportListArrayToExcel(excelFile, title, detailTitleColumns, dataList, firstPage, false, 2, "货物信息", out,
                    writer);
            // 更新页数
            return detailCicleExport(pramsMap, nextPage, excelFile, out, writer);
        } else {
            // 写入最后一页数据
            exportListArrayToExcel(excelFile, title, detailTitleColumns, dataList, firstPage, true, 2, "货物信息", out,
                    writer);
            return hasNext;
        }

    }

    public void exportListArrayToExcel(String excelFile, String title, String[] titleColumns, List<String[]> dataList,
                                       boolean firstPage, boolean lastPage, int sheetNo, String sheetName, OutputStream out, ExcelWriter writer) {

        String[] datas;
        if (firstPage) {
            writeSheet = new WriteSheet();
            writeSheet.setSheetNo(sheetNo);
            writeSheet.setSheetName(sheetName);
            writeTable = new WriteTable();
            writeTable.setTableNo(sheetNo);
            List<List<String>> titles = new ArrayList<>();
            datas = titleColumns;
            int var11 = titleColumns.length;

            for (int var12 = 0; var12 < var11; ++var12) {
                String titleColumn = datas[var12];
                titles.add(Collections.singletonList(titleColumn));
            }

            writeTable.setHead(titles);
            List<List<String>> list = new ArrayList<>();

            for (String[] strings : dataList) {
                datas = strings;
                list.add(Arrays.asList(datas));
            }

            this.writer.write(list, writeSheet, writeTable);
        } else {
            List<List<String>> list = new ArrayList<>();

            for (String[] strings : dataList) {
                datas = strings;
                list.add(Arrays.asList(datas));
            }

            this.writer.write(list, writeSheet, writeTable);
        }

    }

    private static String getFilePath(String fileName) {
        StringBuilder filePath = new StringBuilder();
        if (!fileName.contains(":")) {
            filePath.append("/");
        }

        String[] filePaths = fileName.split("/");

        for (int i = 0; i < filePaths.length - 1; ++i) {
            if (!StringHelper.isBlank(filePaths[i])) {
                filePath.append(filePaths[i]);
                filePath.append("/");
            }
        }

        return filePath.toString();
    }
    public boolean checkList(List<String> list) {
        boolean flag =false;
        if (list == null || list.isEmpty()){
            flag = true;
        }else {
            String s = list.toString().replace("[","").replace("]","");
            if (StringHelper.isBlank(s)){
                flag = true;
            }
            if (StringHelper.isNotBlank(s) && s.contains(",")){
                String replace = s.replace(",", "");
                if (StringHelper.isBlank(replace)){
                    flag = true;
                }
            }
        }
        return flag;
    }
}
