package com.pcloud.book.copyright.biz.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.pcloud.book.base.enums.BookStatusEnum;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.biz.BookBiz;
import com.pcloud.book.book.dto.BookDto;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.common.ExportConsr;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.copyright.biz.BookAuthCodeBiz;
import com.pcloud.book.copyright.biz.BookAuthInfoBiz;
import com.pcloud.book.copyright.biz.BookAuthServeBiz;
import com.pcloud.book.copyright.biz.BookAuthUserBiz;
import com.pcloud.book.copyright.constants.CopyrightConstants;
import com.pcloud.book.copyright.constants.ImportAuthCodeStatus;
import com.pcloud.book.copyright.dao.BookAuthCodeDao;
import com.pcloud.book.copyright.dao.BookAuthCodeImportRecordDao;
import com.pcloud.book.copyright.dto.BookAuthCodeDTO;
import com.pcloud.book.copyright.dto.BookAuthUserDTO;
import com.pcloud.book.copyright.dto.DeleteAuthCodeDTO;
import com.pcloud.book.copyright.entity.BookAuthCode;
import com.pcloud.book.copyright.entity.BookAuthCodeImportRecord;
import com.pcloud.book.copyright.entity.BookAuthUser;
import com.pcloud.book.copyright.enums.AuthBookTypeEnum;
import com.pcloud.book.copyright.tools.ExcelUtil;
import com.pcloud.book.copyright.vo.BookAuthInfoVO;
import com.pcloud.book.copyright.vo.CheckAppServeVO;
import com.pcloud.book.copyright.vo.CheckCodeParam;
import com.pcloud.book.copyright.vo.CheckIsAuthServeParam;
import com.pcloud.book.copyright.vo.FileVO;
import com.pcloud.book.copyright.vo.ImportRecordVO;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.channelcenter.qrcode.vo.MessageAssocBookAskInfoVO;
import com.pcloud.channelcenter.qrcode.vo.MessageAssocBookInfoVO;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.core.biz.MessageBiz;
import com.pcloud.common.core.constant.SystemCode;
import com.pcloud.common.core.dto.SendNotifyDto;
import com.pcloud.common.core.enums.NotifyOriginTypeEnum;
import com.pcloud.common.entity.UploadResultInfo;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.exceptions.ExportException;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.aliyun.OssUtils;
import com.pcloud.common.utils.json.JSONUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.readercenter.wechat.entity.WechatUser;
import com.pcloud.resourcecenter.base.exceptions.ResBizException;
import com.pcloud.settlementcenter.record.exceptions.RecordException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;

import static com.pcloud.book.util.common.ExcelUtils.getColumnTopStyle;
import static com.pcloud.book.util.common.ExcelUtils.getDataStyle;

/**
 * @author lily
 * @date 2018/12/4 19:11
 */
@Component("bookAuthCodeBiz")
public class BookAuthCodeBizImpl implements BookAuthCodeBiz {
    private static final Logger LOGGER = LoggerFactory.getLogger(BookAuthInfoBizImpl.class);
    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(2);
    @Autowired
    private BookAuthCodeDao bookAuthCodeDao;

    @Autowired
    private BookAuthUserBiz bookAuthUserBiz;

    @Autowired
    private BookAuthInfoBiz bookAuthInfoBiz;

    @Autowired
    private BookAuthServeBiz bookAuthServeBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private BookAuthCodeImportRecordDao bookAuthCodeImportRecordDao;
    @Autowired
    private BookBiz bookBiz;
    @Autowired
    private MessageBiz messageBiz;
    @Autowired
    private ExportConsr exportConsr;

    @Override
    @ParamLog(value = "批量插入授权码", isBefore = false)
    public void insert(List<BookAuthCode> bookAuthCodes) {
        int insertLength = bookAuthCodes.size();
        int i = 0;
        while (insertLength > 5000) {
            bookAuthCodeDao.insert(bookAuthCodes.subList(i, i + 5000));
            i = i + 5000;
            insertLength = insertLength - 5000;
        }
        if (insertLength > 0) {
            bookAuthCodeDao.insert(bookAuthCodes.subList(i, i + insertLength));
        }
    }

    @Override
    public Integer getMaxBatchNum(Long bookId, Long channelId, Long adviserId, Integer authBookType) {
        Integer batchNum = bookAuthCodeDao.getMaxBatchNum(bookId, channelId, adviserId, authBookType);
        return batchNum;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer checkCode(CheckCodeParam checkCodeParam, Long channelId, Long wechatUserId) {
        String code = checkCodeParam.getCode();
        Integer authBookType = checkCodeParam.getAuthBookType();
        if (StringUtils.isEmpty(code) || code.length() != 15) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "此码错误，请重新验证");
        }
        BookAuthInfoVO authBookInfo = bookAuthInfoBiz.getAuthBookInfo(checkCodeParam.getBookId(), channelId, checkCodeParam.getAdviserId(), checkCodeParam.getSceneId(), authBookType);
        if (authBookInfo == null || BookStatusEnum.NO_SET.value.equals(authBookInfo.getBookStatus())) {
            return BookStatusEnum.CodeUseTypeEnum.RIGHT.value;
        }
        Long bookId = authBookInfo.getBookId();
        Long adviserId = authBookInfo.getAdviserId();
        //校验用户是否已经授权过
        Boolean isHaveAuth = bookAuthUserBiz.checkIsHaveAuth(bookId, channelId, adviserId, wechatUserId, authBookType,null,null);
        if (isHaveAuth) {
            return BookStatusEnum.CodeUseTypeEnum.RIGHT.value;
        }
        Long authCodeId = bookAuthCodeDao.getBookAuthCodeId(bookId, channelId, adviserId, code, authBookType);
        Integer count = bookAuthCodeDao.updateUseCount(bookId, channelId, adviserId, code, authBookInfo.getCodeUseCount(), authBookType);
        if (count < 1 && authCodeId != null && authCodeId > 0) {
            return BookStatusEnum.CodeUseTypeEnum.HAVE_USE.value;
        } else if (count < 1 && (authCodeId == null || authCodeId == 0)) {
            return BookStatusEnum.CodeUseTypeEnum.NOT_RIGHT.value;
        } else {
            //新增一条校验成功记录
            addUserRecord(bookId, channelId, adviserId, wechatUserId, authBookType, authCodeId);
            return BookStatusEnum.CodeUseTypeEnum.RIGHT.value;
        }
    }

    @Override
    @ParamLog(value = "校验服务是否需要验证", isAfterReturn = false)
    public Boolean checkServe(CheckIsAuthServeParam checkIsAuthServeParam, Long channelId, Long wechatUserId) {
        Long serveId = checkIsAuthServeParam.getServeId();
        String serveType = checkIsAuthServeParam.getServeType();
        if (serveId == null || serveType == null) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择要进入的服务");
        }
        //校验图书是否开启保护
        BookAuthInfoVO authBookInfo = bookAuthInfoBiz.getAuthBookInfo(checkIsAuthServeParam.getBookId(), channelId, checkIsAuthServeParam.getAdviserId(), checkIsAuthServeParam.getSceneId(),null);
        if (authBookInfo == null || BookStatusEnum.NO_SET.value.equals(authBookInfo.getBookStatus())) {
            return false;
        }
        Long bookId = authBookInfo.getBookId();
        Long adviserId = authBookInfo.getAdviserId();
        List<Long> serveIds = new ArrayList<>();
        serveIds.add(serveId);
        Map<String, Boolean> isHaveServe = qrcodeSceneConsr.listIsInBook(bookId, channelId, adviserId, serveIds);
        if (isHaveServe == null) {
            return false;
        }
        //校验服务是否需要授权
        Boolean isNeedAuth = bookAuthServeBiz.checkIsNeedAuth(bookId, channelId, adviserId, serveId, serveType);
        if (!isNeedAuth) {
            return false;
        }
        //校验用户是否已经授权过
        Boolean isHaveAuth = bookAuthUserBiz.checkIsHaveAuth(bookId, channelId, adviserId, wechatUserId,null,null,null);
        return !isHaveAuth;
    }

    @Override
    @ParamLog("导入授权码")
    public void importCode(FileVO fileVO, Long adviserId) throws BizException {
        //新增导入记录
        BookAuthCodeImportRecord bookAuthCodeImportRecord = new BookAuthCodeImportRecord();
        bookAuthCodeImportRecord.setBookId(fileVO.getBookId());
        bookAuthCodeImportRecord.setAdviserId(adviserId);
        bookAuthCodeImportRecord.setChannelId(fileVO.getChannelId());
        bookAuthCodeImportRecord.setCreateUser(adviserId);
        bookAuthCodeImportRecord.setFileName(fileVO.getFileName());
        bookAuthCodeImportRecord.setFileUrl(fileVO.getFileUrl());
        Integer authBookType = fileVO.getAuthBookType();
        if(authBookType == null || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)) {
            bookAuthCodeImportRecord.setIsPaperBook(1);
            bookAuthCodeImportRecord.setIsGroupBook(0);
        } else {
            bookAuthCodeImportRecord.setIsPaperBook(0);
            bookAuthCodeImportRecord.setIsGroupBook(1);
        }
        bookAuthCodeImportRecordDao.insert(bookAuthCodeImportRecord);
        ThreadPoolUtils.EXPORT_THREAD_POOL.execute(() -> {
            Integer isFinish = 1;
            try {
                String[][] data = ExcelUtil.getData(fileVO.getFileUrl(), 3);
                if (data != null) {
                    List<BookAuthCode> bookAuthCodes = new ArrayList<>();
                    for (int i = 0, size = data.length; i < size; i++) {
                        BookAuthCode bookAuthCode = new BookAuthCode();
                        if(authBookType == null || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)) {
                            bookAuthCode.setIsPaperBook(1);
                            bookAuthCode.setIsGroupBook(0);
                        } else {
                            bookAuthCode.setIsPaperBook(0);
                            bookAuthCode.setIsGroupBook(1);
                        }
                        bookAuthCode.setBookId(fileVO.getBookId());
                        bookAuthCode.setChannelId(fileVO.getChannelId());
                        bookAuthCode.setAdviserId(adviserId);
                        String fullCode = data[i][1];
                        bookAuthCode.setFullCode(fullCode);
                        if (fullCode == null || fullCode.length() < 15) {
                            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "授权码错误");
                        }
                        bookAuthCode.setBatchNum(fullCode.substring(0, 4));
                        bookAuthCode.setAuthCode(fullCode.substring(4, data[i][1].length()));
                        bookAuthCode.setUseCount(0);
                        bookAuthCode.setCreateType(1);
                        bookAuthCode.setCreatedUser(adviserId);
                        bookAuthCodes.add(bookAuthCode);
                    }
                    insert(bookAuthCodes);
                }else{
                    isFinish = ImportAuthCodeStatus.FAIL.value;
                }
            } catch (Exception e) {
                isFinish = ImportAuthCodeStatus.FAIL.value;
                LOGGER.error("导入失败" + e.getMessage(), e);
            }finally {
                bookAuthCodeImportRecordDao.updateState(bookAuthCodeImportRecord.getId(), isFinish);
                //发送站内信
                sendImportRecord(isFinish, fileVO.getBookId(),fileVO.getChannelId(), adviserId);
            }
        });
    }

    private void sendImportRecord(Integer isFinish, Long bookId, Long channelId, Long adviserId) {
        BookDto bookDto = bookBiz.getBaseById(bookId);
        SendNotifyDto sendNotifyDto = new SendNotifyDto();
        sendNotifyDto.setCreatedTime(new Date());
        JSONObject content = new JSONObject();
        if (isFinish == ImportAuthCodeStatus.SUCCESS.value) {
            content.put("result", "成功");
        } else {
            content.put("result", "失败");
        }
        content.put("bookName", "[" + bookDto.getBookName() + "]");
        sendNotifyDto.setNotifyContent(content.toJSONString());
        sendNotifyDto.setToId(adviserId);
        sendNotifyDto.setFromId(adviserId);
        sendNotifyDto.setResourceId(bookId + "-" + channelId);
        sendNotifyDto.setOriginType(NotifyOriginTypeEnum.GENUINE.value);
        sendNotifyDto.setSystemCode(SystemCode.adviser.code);
        sendNotifyDto.setTypeCode("genuine_qrcord_import_result");
        messageBiz.sendLetter(sendNotifyDto);
    }

    @Override
    @ParamLog("导入记录")
    public PageBeanNew<ImportRecordVO> importCodeRecord(Long bookId, Long channelId, Long adviserId, Integer authBookType, Integer currentPage, Integer numPerPage) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", adviserId);
        if(null == authBookType || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)){
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        PageParam pageParam = new PageParam(currentPage, numPerPage);
        return bookAuthCodeImportRecordDao.listPageNew(pageParam, paramMap, "importCodeRecord");
    }

    @ParamLog("新增一条授权成功记录")
    private void addUserRecord(Long bookId, Long channelId, Long adviserId, Long wechatUserId, Integer authBookType, Long bookAuthCodeId) {
        BookAuthUser bookAuthUser = new BookAuthUser();
        bookAuthUser.setBookId(bookId);
        bookAuthUser.setChannelId(channelId);
        bookAuthUser.setAdviserId(adviserId);
        bookAuthUser.setWechatUserId(wechatUserId);
        bookAuthUser.setAuthCode(BookStatusEnum.AuthCodeTypeEnum.BY_CODE.value);
        bookAuthUser.setBookAuthCodeId(bookAuthCodeId);
        WechatUser wechatUser = readerConsr.getWechatUser(wechatUserId);
        bookAuthUser.setProvince(wechatUser == null || StringUtil.isEmpty(wechatUser.getWechatUserProvince()) ? "未知" : wechatUser.getWechatUserProvince());
        bookAuthUser.setCity(wechatUser == null || StringUtil.isEmpty(wechatUser.getWechatUserCity()) ? "未知" : wechatUser.getWechatUserCity());
        if(authBookType == null || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)) {
            bookAuthUser.setIsPaperBook(1);
            bookAuthUser.setIsGroupBook(0);
        } else {
            bookAuthUser.setIsGroupBook(1);
            bookAuthUser.setIsPaperBook(0);
        }
        bookAuthUserBiz.insert(bookAuthUser);
    }

    /**
     * 获取正版授权码
     * @param bookId
     * @param channelId
     * @param keyword
     * @param state
     * @param pageParam
     * @return
     */
    @Override
    @ParamLog("获取正版授权码")
    public PageBeanNew<BookAuthCodeDTO> getCodeList(Long bookId, Long channelId, Long adviserId, String keyword, Integer state, Integer authBookType, PageParam pageParam) {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("bookId",bookId);
        paramMap.put("channelId",channelId);
        paramMap.put("adviserId",adviserId);
        paramMap.put("keyword",StringUtil.isEmpty(keyword)?null:keyword);
        paramMap.put("state",state);
        if(null == authBookType || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)){
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        PageBeanNew<BookAuthCodeDTO> pageBeanNew = bookAuthCodeDao.listPageNew(pageParam, paramMap, "getCodeList");
        if(pageBeanNew == null || CollectionUtils.isEmpty(pageBeanNew.getRecordList())){
            return pageBeanNew;
        }
        List<BookAuthCodeDTO> recordList = pageBeanNew.getRecordList();
        // 填充
        this.fillAuthUser(recordList);
        return pageBeanNew;
    }

    /**
     * 填充用户
     * @param recordList
     */
    private void fillAuthUser(List<BookAuthCodeDTO> recordList) {
        List<Long> authCodeIds = recordList.stream().filter(x-> x.getUseCount() > 0).map(x -> x.getId()).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(authCodeIds)){
            return;
        }
        // 查询使用码的使用情况
        Map<Long, List<BookAuthUserDTO>> authUserMap = bookAuthUserBiz.getByAuthCodeIds(authCodeIds,null);
        for (BookAuthCodeDTO bookAuthCodeDTO : recordList) {
            bookAuthCodeDTO.setBookAuthUserList(authUserMap.getOrDefault(bookAuthCodeDTO.getId(), Lists.newArrayList()));
        }
    }

    /**
     * 批量删除正版授权码
     * @param ids
     */
    @Override
    @ParamLog("批量删除正版授权码")
    public void batchDeleteCode(List<Long> ids) {
        bookAuthCodeDao.batchDeleteCode(ids);
    }

    @Override
    @ParamLog("导出授权码")
    public Map<String, Object> getCodeExcel(Long bookId, String codeIds, Long channelId, Long status,
                                            String systemCode, Long partyId, Integer authBookType) {
        //获取书的基本信息
        BookDto bookDto = bookBiz.getBaseById(bookId);
        if (null == bookDto || null == bookDto.getBookId()){
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "授权码所对应的书不存在");
        }
        //表名
        String title = "《" + bookDto.getBookName() + "》" + "的授权码";
        String[] rowsName = {"序号", "完整授权码", "生成方式", "状态", "创建时间"};
        String fileUrl = "";
        String finalTitle = title;
        //不管是全部导出还是导出部分，都使用异步处理
        if (status == 0) {
            EXECUTOR_SERVICE.execute(() -> {
                String filePath = this.exportAllFreeCode(finalTitle, rowsName, bookId, channelId, partyId, authBookType);
                //发送站内信
                SendNotifyDto sendNotifyDto = new SendNotifyDto();
                sendNotifyDto.setCreatedTime(new Date());
                JSONObject content = new JSONObject();
                content.put("commitTime", DateUtils.getSysDateTimeString());
                content.put("type", StringUtil.addBracket(bookDto.getBookName()));
                sendNotifyDto.setNotifyContent(content.toJSONString());
                sendNotifyDto.setToId(partyId);
                sendNotifyDto.setFromId(partyId);
                sendNotifyDto.setSystemCode(systemCode);
                sendNotifyDto.setTypeCode("genuine_qrcord_download");
                sendNotifyDto.setFileName(bookDto.getBookName());
                sendNotifyDto.setResourceId(filePath);
                messageBiz.sendLetter(sendNotifyDto);
            });
        } else if (status == 1) {
            EXECUTOR_SERVICE.execute(() -> {
                String filePath = this.exportFreeCodeSelected(finalTitle, rowsName, codeIds);
                //发送站内信
                SendNotifyDto sendNotifyDto = new SendNotifyDto();
                sendNotifyDto.setCreatedTime(new Date());
                Map<String, String> map = new HashMap<>();
                map.put("commitTime", DateUtils.getSysDateTimeString());
                map.put("type", StringUtil.addBracket(bookDto.getBookName()));
                String content = JSONUtils.toJsonString(map);
                sendNotifyDto.setNotifyContent(content);
                sendNotifyDto.setFileName(finalTitle);
                sendNotifyDto.setFromId(partyId);
                sendNotifyDto.setToId(partyId);
                sendNotifyDto.setSystemCode(systemCode);
                sendNotifyDto.setTypeCode("genuine_qrcord_download");
                sendNotifyDto.setFileName(bookDto.getBookName());
                sendNotifyDto.setResourceId(filePath);
                messageBiz.sendLetter(sendNotifyDto);
            });
        }
        Map<String, Object> returnInfo = new HashMap<>();
        returnInfo.put("fileUrl", fileUrl);
        returnInfo.put("fileName", title);
        return returnInfo;
    }

    /**
     * 导出选中的授权码
     * @param title
     * @param rowsName
     * @param codeIds
     * @return
     */
    private String exportFreeCodeSelected(String title, String[] rowsName, String codeIds){
        //导出选中的
        List<String> rowsNameList = Arrays.asList(rowsName);
        List<Object[]> dataList = new ArrayList<>();
        String fileUrl = "";
        if (!StringUtils.isBlank(codeIds)) {
            //切割CodeIds
            String[] codeId = codeIds.split(",");
            //根据购物码id查询购物码信息
            for (int i = 0; i < codeId.length; i++) {
                BookAuthCodeDTO bookAuthCode = bookAuthCodeDao.getBaseById(Long.parseLong(codeId[i]));
                if (null == bookAuthCode) {
                    throw new ResBizException(ResBizException.PARAM_IS_ERROR, "授权码不存在");
                }
                Object[] objs = new Object[rowsNameList.size()];
                objs[0] = i + 1;
                //objs[1] = bookAuthCode.getAuthCode();
                objs[1] = bookAuthCode.getFullCode();
                CopyrightConstants.CreateType createType = CopyrightConstants.CreateType.CRATE_TYPE_MAP.get(bookAuthCode.getCreateType());
                objs[2] = null == createType ? "-" : createType.getName();
                objs[3] = bookAuthCode.getUseCount() > 0 ? "已使用" : "未使用";
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                objs[4] = bookAuthCode.getCreatedDate() != null ? df.format(bookAuthCode.getCreatedDate()) : "";
                dataList.add(objs);
                fileUrl = exportConsr.exportExcel(title, rowsName, dataList);
            }
        } else {
            throw new ResBizException(ResBizException.PARAM_IS_ERROR, "授权码不存在");
        }
        return fileUrl;
    }
    /**
     * 导出所有授权码
     * @param title
     * @param rowsName
     * @param bookId
     * @param channelId
     * @param partyId
     * @return
     */
    private String exportAllFreeCode(String title, String[] rowsName, Long bookId, Long channelId, Long partyId, Integer authBookType) {
        SXSSFWorkbook wb = new SXSSFWorkbook(200);
        int columnNum = rowsName.length;
        int rowIndex = 0;
        SXSSFRow row;
        SXSSFCell cell;
        //设置表头样式
        CellStyle headerStyle = getColumnTopStyle(wb);
        SXSSFSheet sheet = wb.createSheet();
        row = sheet.createRow(rowIndex);
        cell = row.createCell(0);
        //合并前两行
        sheet.addMergedRegion(new CellRangeAddress(rowIndex, ++rowIndex, 0, columnNum - 1));
        cell.setCellStyle(headerStyle);
        cell.setCellValue(title);
        //设置属性
        row = sheet.createRow(++rowIndex);
        for (int i = 0; i < rowsName.length; ++i) {
            sheet.setColumnWidth(i, 20 * 256);
            cell = row.createCell(i);
            cell.setCellStyle(headerStyle);
            cell.setCellValue(rowsName[i]);
        }
        //设置数据样式
        CellStyle dataStyle = getDataStyle(wb);
        dataStyle.setAlignment(HorizontalAlignment.CENTER);

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", partyId);
        if(authBookType == null || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)) {
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int k = 1;
        //分批导出
        for (int j = 0; true; j++) {
            paramMap.put("currentPage", j * 500);
            paramMap.put("numPerPage", 500);
            List<BookAuthCodeDTO> bookAuthCodeDtos = bookAuthCodeDao.getBookAuthCodeList(paramMap);
            if (!ListUtils.isEmpty(bookAuthCodeDtos)) {
                for (BookAuthCodeDTO bookAuthCodeDTO : bookAuthCodeDtos) {
                    SXSSFRow srow = sheet.createRow(++rowIndex);
                    SXSSFCell cell0 = srow.createCell(0);
                    cell0.setCellStyle(dataStyle);
                    cell0.setCellValue(k++);
                    /*SXSSFCell cell1 = srow.createCell(1);
                    cell1.setCellStyle(dataStyle);
                    cell1.setCellValue(bookAuthCodeDTO.getAuthCode());*/
                    SXSSFCell cell2 = srow.createCell(1);
                    cell2.setCellStyle(dataStyle);
                    cell2.setCellValue(bookAuthCodeDTO.getFullCode());
                    SXSSFCell cell3 = srow.createCell(2);
                    cell3.setCellStyle(dataStyle);
                    CopyrightConstants.CreateType createType = CopyrightConstants.CreateType.CRATE_TYPE_MAP.get(bookAuthCodeDTO.getCreateType());
                    cell3.setCellValue(null == createType ? "-" : createType.getName());
                    SXSSFCell cell4 = srow.createCell(3);
                    cell4.setCellStyle(dataStyle);
                    cell4.setCellValue(bookAuthCodeDTO.getUseCount() > 0 ? "已使用" : "未使用");
                    SXSSFCell cell5 = srow.createCell(4);
                    cell5.setCellStyle(dataStyle);
                    cell5.setCellValue(bookAuthCodeDTO.getCreatedDate() != null ? df.format(bookAuthCodeDTO.getCreatedDate()) : "");
                }
            }
            if (bookAuthCodeDtos.size() < 500) {
                break;
            }
            bookAuthCodeDtos.clear();
        }
        //上传文件
        String fileUrl = "";
        try {
            String UID = UUID.randomUUID().toString();
            String path = UID + ".xlsx";
            FileOutputStream fileOut = new FileOutputStream(path);
            wb.write(fileOut);
            fileOut.flush();
            fileOut.close();
            wb.close();
            UploadResultInfo uploadResultInfo = OssUtils.uploadLocalFile(path, "xlsx");
            fileUrl = uploadResultInfo.getUrl();
            LOGGER.info("=======fileUrl==========" + OssUtils.urlAddKeyLong(fileUrl));
            new File(path).delete();
        } catch (FileNotFoundException e) {
            LOGGER.error("临时文件Excel路径找不到" + e.getMessage(), e);
            throw new ExportException(RecordException.ERROR, "导出Excel失败");
        } catch (IOException e) {
            LOGGER.error("生成临时文件Excel异常" + e.getMessage(), e);
            throw new ExportException(RecordException.ERROR, "导出Excel失败");
        }
        return fileUrl;
    }

    @Override
    public void deleteNoUsedAuthCode(DeleteAuthCodeDTO deleteAuthCodeDTO, Long adviserId) {
        List<Long> codeIds=bookAuthCodeDao.getCodeIdList(deleteAuthCodeDTO.getBookId(),deleteAuthCodeDTO.getChannelId(),adviserId,deleteAuthCodeDTO.getKeyWord(), deleteAuthCodeDTO.getAuthBookType());
        if(CollectionUtils.isEmpty(codeIds)){
            return;
        }
        this.batchDeleteCode(codeIds);
    }

    @Override
    public CheckAppServeVO checkAppServe(CheckIsAuthServeParam checkIsAuthServeParam, Long channelId, Long wechatUserId) {
        if (ObjectUtil.hasEmpty(checkIsAuthServeParam,checkIsAuthServeParam.getServeId(),checkIsAuthServeParam.getServeType())) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择要进入的服务");
        }
        CheckAppServeVO result=new CheckAppServeVO();
        Long serveId = checkIsAuthServeParam.getServeId();
        String serveType = checkIsAuthServeParam.getServeType();
        Long adviserId=checkIsAuthServeParam.getAdviserId();
        //1。先根据应用信息找到最近挂的一本书
        MessageAssocBookAskInfoVO vo=new MessageAssocBookAskInfoVO();
        vo.setAdviserId(adviserId);
        vo.setFromId(serveId);
        vo.setTypeCode(serveType);
        Map<String, MessageAssocBookInfoVO> infoByServe = qrcodeSceneConsr.getLastBookInfoByServe(Lists.newArrayList(vo));
        Long bookId=null;
        Long sceneId=null;
        String key = serveType + serveId;
        if(CollUtil.isNotEmpty(infoByServe) && infoByServe.containsKey(key)){
            MessageAssocBookInfoVO messageAssocBookInfoVO = infoByServe.get(key);
            if(null!=messageAssocBookInfoVO){
                bookId=messageAssocBookInfoVO.getBookId();
                channelId=messageAssocBookInfoVO.getChannelId();
                sceneId=messageAssocBookInfoVO.getSceneId();
            }
        }
        //校验图书是否开启保护
        BookAuthInfoVO authBookInfo = bookAuthInfoBiz.getAuthBookInfo(bookId, channelId, adviserId, null,null);
        if (authBookInfo == null || BookStatusEnum.NO_SET.value.equals(authBookInfo.getBookStatus())) {
            result.setNeedCheck(false);
            return result;
        }
        //升级版的版权保护不需要验证
        if (null!=authBookInfo.getAuthType() && 2==authBookInfo.getAuthType()) {
            result.setNeedCheck(false);
            return result;
        }
        bookId = authBookInfo.getBookId();
        adviserId = authBookInfo.getAdviserId();
        List<Long> serveIds = new ArrayList<>();
        serveIds.add(serveId);
        Map<String, Boolean> isHaveServe = qrcodeSceneConsr.listIsInBook(bookId, channelId, adviserId, serveIds);
        if (isHaveServe == null) {
            result.setNeedCheck(false);
            return result;
        }
        //校验服务是否需要授权
        Boolean isNeedAuth = bookAuthServeBiz.checkIsNeedAuth(bookId, channelId, adviserId, serveId, serveType);
        if (!isNeedAuth) {
            result.setNeedCheck(false);
            return result;
        }
        //校验用户是否已经授权过
        Boolean isHaveAuth = bookAuthUserBiz.checkIsHaveAuth(bookId, channelId, adviserId, wechatUserId,null,null,null);
        result.setNeedCheck(!isHaveAuth);
        result.setAdviserId(adviserId);
        result.setChannelId(channelId);
        result.setBookId(bookId);
        result.setSceneId(sceneId);
        return result;
    }
}
