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

import com.google.common.collect.Lists;

import com.alibaba.fastjson.JSONObject;
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.constant.BookConstant;
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.BookAuthInfoBiz;
import com.pcloud.book.copyright.biz.BookAuthUserBiz;
import com.pcloud.book.copyright.biz.BookExportRecordBiz;
import com.pcloud.book.copyright.biz.BookSceneAuthBiz;
import com.pcloud.book.copyright.constants.CopyrightConstants;
import com.pcloud.book.copyright.dao.BookAuthUserDao;
import com.pcloud.book.copyright.dao.BookSceneAuthCodeDao;
import com.pcloud.book.copyright.dao.BookSceneAuthDao;
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.dto.SceneAuthCodeResponseDTO;
import com.pcloud.book.copyright.dto.SceneAuthCodeSearchDTO;
import com.pcloud.book.copyright.entity.BookAuthUser;
import com.pcloud.book.copyright.entity.BookExportRecord;
import com.pcloud.book.copyright.entity.BookSceneAuth;
import com.pcloud.book.copyright.entity.BookSceneAuthCode;
import com.pcloud.book.copyright.enums.AuthBookTypeEnum;
import com.pcloud.book.copyright.tools.CopyrightTools;
import com.pcloud.book.copyright.vo.BookAuthInfoVO;
import com.pcloud.book.copyright.vo.CheckAuthCodeVO;
import com.pcloud.book.copyright.vo.GenerateCodeVO;
import com.pcloud.book.copyright.vo.UseAuthCodeVO;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.channelcenter.qrcode.dto.QrcodeSceneDto;
import com.pcloud.common.core.biz.MessageBiz;
import com.pcloud.common.core.dto.SendNotifyDto;
import com.pcloud.common.entity.UploadResultInfo;
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.cache.redis.JedisClusterUtils;
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.Service;
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.function.Function;
import java.util.stream.Collectors;

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

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

/**
 * 书籍二维码授权表(BookSceneAuth)表服务实现类
 *
 * @author makejava
 * @since 2021-10-19 14:14:22
 */
@Service("bookSceneAuthBiz")
public class BookSceneAuthBizImpl implements BookSceneAuthBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(BookSceneAuthBizImpl.class);
    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(2);

    @Autowired
    private BookSceneAuthDao bookSceneAuthDao;
    @Autowired
    private BookSceneAuthCodeDao bookSceneAuthCodeDao;
    @Autowired
    private BookBiz bookBiz;
    @Autowired
    private BookAuthInfoBiz bookAuthInfoBiz;
    @Autowired
    private BookExportRecordBiz bookExportRecordBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private BookAuthUserBiz bookAuthUserBiz;
    @Autowired
    private BookAuthUserDao bookAuthUserDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private MessageBiz messageBiz;
    @Autowired
    private ExportConsr exportConsr;

    /**
     *  自动创建授权码
     */
    @Override
    public void autoGenerateAuthCode(GenerateCodeVO generateCodeVO, Long adviserId) {
        if (ObjectUtil.hasEmpty(generateCodeVO, generateCodeVO.getBookId(), generateCodeVO.getSceneId(), generateCodeVO.getCodeCount())) {
            return;
        }
        Integer codeCount = generateCodeVO.getCodeCount();
        Long bookId = generateCodeVO.getBookId();
        Integer authBookType = generateCodeVO.getAuthBookType();
        Long channelId = generateCodeVO.getChannelId();
        Long sceneId = generateCodeVO.getSceneId();
        String key = BookConstant.BOOK_AUTH_CODE_CACHE + "_" + generateCodeVO.getBookId() + "_" + channelId + "_" + adviserId + "_" + sceneId;
        if (null != JedisClusterUtils.get(key)) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "本书有授权码正在生成中，请稍后再试！");
        }
        QrcodeSceneDto sceneDto = qrcodeSceneConsr.getById(sceneId);
        if (null == sceneDto || null == sceneDto.getUrl()) {
            return;
        }
        if (codeCount == null || codeCount == 0) {
            return;
        }
        if (codeCount > 1000) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "单次生成数量不要超过1000！");
        }
        ThreadPoolUtils.EXPORT_THREAD_POOL.execute(() -> {
            String commitTime = DateUtils.formatDate(new Date());
            String num = "";
            try {
                JedisClusterUtils.set(key, codeCount.toString(), 60 * 60);
                //获取批次号
                Integer batchNum = bookSceneAuthCodeDao.getMaxBatchNum(bookId, channelId, sceneId, adviserId, authBookType);
                num = String.format("%04d", batchNum);
                //新增导出记录
                insertExportRecord(bookId, channelId, adviserId, num, codeCount, sceneId);
                //获取图书名称
                BookDto bookDto = bookBiz.getBaseById(bookId);
                if (bookDto == null) {
                    return;
                }
                //获取随机数
                List<String> uuids = CopyrightTools.createShortUuidByCount(codeCount);
                List<BookSceneAuthCode> bookAuthCodes = new ArrayList<>();
                for (String uuid : uuids) {
                    BookSceneAuthCode bookAuthCode = new BookSceneAuthCode();
                    if (authBookType == null || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)) {
                        bookAuthCode.setIsPaperBook(1);
                        bookAuthCode.setIsGroupBook(0);
                    } else {
                        bookAuthCode.setIsPaperBook(0);
                        bookAuthCode.setIsGroupBook(1);
                    }
                    bookAuthCode.setAdviserId(adviserId);
                    bookAuthCode.setChannelId(channelId);
                    bookAuthCode.setBookId(bookId);
                    bookAuthCode.setAuthCode(uuid);
                    bookAuthCode.setFullCode(num + uuid);
                    bookAuthCode.setBatchNum(num);
                    bookAuthCode.setCreateType(0);
                    bookAuthCode.setCreatedUser(adviserId);
                    bookAuthCode.setSceneId(sceneId);
                    bookAuthCodes.add(bookAuthCode);
                }
                bookSceneAuthCodeDao.insert(bookAuthCodes);
                String bookName=bookDto.getBookName() +"_"+sceneDto.getSceneName();
                String noticeUrl;
                String zipUrl = CopyrightTools.generateQrcode4ZipNew(bookAuthCodes, bookDto.getBookName(), sceneDto.getSceneName(),sceneDto.getUrl(), authBookType);
                noticeUrl = zipUrl;
                //发送站内信
                bookAuthInfoBiz.sendLetter(adviserId, bookName, noticeUrl, commitTime);
                //新增导出记录
                updateSuccessRecord(bookId, channelId, adviserId, num, noticeUrl, sceneId);
                BookSceneAuth authSceneInfo = bookSceneAuthDao.getAuthSceneInfo(bookId, sceneId);
                if (null == authSceneInfo) {
                    BookSceneAuth build = BookSceneAuth.builder().bookId(bookId).adviserId(adviserId).channelId(channelId).sceneId(sceneId)
                            .maxUserCount(2).createdUser(adviserId).build();
                    bookSceneAuthDao.insert(build);
                }
                //更新授权二维码到数据库
                if (CollUtil.isNotEmpty(bookAuthCodes)) {
                    if (StrUtil.isNotBlank(bookAuthCodes.get(0).getQrcodeUrl())) {
                        bookSceneAuthCodeDao.batchUpdate(bookAuthCodes);
                    }
                }
                LOGGER.info("url" + noticeUrl);
            } catch (Exception e) {
                LOGGER.error("导出授权码失败" + e.getMessage(), e);
                updateExportRecord(bookId, channelId, adviserId, num, BookStatusEnum.BookExportStatus.FAIL.value, sceneId); //TODO
            } finally {
                JedisClusterUtils.del(key);
            }
        });
    }

    private void updateExportRecord(Long bookId, Long channelId, Long adviserId, String num, Integer exportStatus,Long sceneId) {
        if(StringUtil.isEmpty(num)) {
            return;
        }
        BookExportRecord bookExportRecord = new BookExportRecord();
        bookExportRecord.setBookId(bookId);
        bookExportRecord.setAdviserId(adviserId);
        bookExportRecord.setBatchNum(num);
        bookExportRecord.setChannelId(channelId);
        bookExportRecord.setLastModifiedUser(adviserId);
        bookExportRecord.setExportStatus(exportStatus);
        bookExportRecord.setSceneId(sceneId);
        bookExportRecordBiz.updateRecordStatus(bookExportRecord);
    }

    private void updateSuccessRecord(Long bookId, Long channelId, Long adviserId, String num, String noticeUrl,Long sceneId) {
        BookExportRecord bookExportRecord = new BookExportRecord();
        bookExportRecord.setBookId(bookId);
        bookExportRecord.setAdviserId(adviserId);
        bookExportRecord.setChannelId(channelId);
        bookExportRecord.setLastModifiedUser(adviserId);
        bookExportRecord.setExportStatus(BookStatusEnum.BookExportStatus.SUCCESS.value);
        bookExportRecord.setDownloadUrl(noticeUrl);
        bookExportRecord.setBatchNum(num);
        bookExportRecord.setSceneId(sceneId);
        bookExportRecordBiz.updateRecord(bookExportRecord);
    }
    private void insertExportRecord(Long bookId, Long channelId, Long adviserId, String num, Integer codeCount, Long sceneId) {
        BookExportRecord bookExportRecord = new BookExportRecord();
        bookExportRecord.setBookId(bookId);
        bookExportRecord.setAdviserId(adviserId);
        bookExportRecord.setChannelId(channelId);
        bookExportRecord.setBatchNum(num);
        bookExportRecord.setCodeCount(codeCount);
        bookExportRecord.setSceneId(sceneId);
        bookExportRecordBiz.insertRecord(bookExportRecord);
    }

    @Override
    public PageBeanNew<BookAuthCodeDTO> listSceneAuthCode(Long bookId, Long channelId, Long sceneId, String keyword, Integer state, Integer authBookType, Integer currentPage, Integer numPerPage, Long adviserId) {
        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);
        paramMap.put("sceneId",sceneId);
        if(null == authBookType || AuthBookTypeEnum.PAPER_BOOK.value.equals(authBookType)){
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        PageBeanNew<BookAuthCodeDTO> pageBeanNew = bookSceneAuthCodeDao.listPageNew(new PageParam(currentPage,numPerPage), paramMap, "listSceneAuthCode");
        if(pageBeanNew == null || CollUtil.isEmpty(pageBeanNew.getRecordList())){
            return new PageBeanNew<>(currentPage,numPerPage,null==pageBeanNew ? 0 : pageBeanNew.getTotalCount(),new ArrayList<>());
        }
        List<BookAuthCodeDTO> recordList = pageBeanNew.getRecordList();
        // 填充
        fillAuthUser(recordList,sceneId);
        return pageBeanNew;
    }

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

    @Override
    public void deleteSceneAuthCode(List<Long> ids) {
        bookSceneAuthCodeDao.deleteSceneAuthCode(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearNoUsedAuthCode(DeleteAuthCodeDTO deleteAuthCodeDTO, Long adviserId) {
        List<Long> codeIds=bookSceneAuthCodeDao.getCodeIdList(deleteAuthCodeDTO.getBookId(),deleteAuthCodeDTO.getChannelId(),adviserId,deleteAuthCodeDTO.getKeyWord(), deleteAuthCodeDTO.getAuthBookType(),deleteAuthCodeDTO.getSceneId());
        if(CollUtil.isEmpty(codeIds)){
            return;
        }
        this.deleteSceneAuthCode(codeIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CheckAuthCodeVO checkSceneAuthCode(UseAuthCodeVO useAuthCodeVO, Long channelId, Long wechatUserId) {
        String code = useAuthCodeVO.getAuthCode();
        if (StringUtils.isEmpty(code) || code.length() != 15) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "此码错误，请重新验证");
        }
        BookSceneAuthCode bookSceneAuthCode = bookSceneAuthCodeDao.getByCode(code);
        CheckAuthCodeVO result=new CheckAuthCodeVO();
        if(null==bookSceneAuthCode){
            result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.NOT_RIGHT.value);
            return result;
        }
        BookSceneAuth authSceneInfo = bookSceneAuthDao.getAuthSceneInfo(bookSceneAuthCode.getBookId(), bookSceneAuthCode.getSceneId());
        if(null==authSceneInfo){
            result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.NOT_RIGHT.value);
            return result;
        }
        channelId=authSceneInfo.getChannelId();
        BookAuthInfoVO authBookInfo = bookAuthInfoBiz.getAuthBookInfo(bookSceneAuthCode.getBookId(), channelId, bookSceneAuthCode.getAdviserId(), bookSceneAuthCode.getSceneId(), useAuthCodeVO.getAuthBookType());
        if (authBookInfo == null || BookStatusEnum.NO_SET.value.equals(authBookInfo.getBookStatus())) {
            result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.RIGHT.value);
            return result;
        }
        //校验用户是否已经授权过
        Boolean isHaveAuth = bookAuthUserBiz.checkIsHaveAuth(bookSceneAuthCode.getBookId(), channelId, bookSceneAuthCode.getAdviserId(), wechatUserId, useAuthCodeVO.getAuthBookType(),bookSceneAuthCode.getSceneId(),bookSceneAuthCode.getId());
        if (isHaveAuth) {
            result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.RIGHT.value);
            return result;
        }
        //判断激活人数是否已经满了
        Integer sceneAuthUserCount = bookAuthUserDao.getSceneAuthUserCount(bookSceneAuthCode.getBookId(), channelId, bookSceneAuthCode.getAdviserId(), useAuthCodeVO.getAuthBookType(), bookSceneAuthCode.getSceneId(),bookSceneAuthCode.getId());
        if(null!=authSceneInfo.getMaxUserCount() && authSceneInfo.getMaxUserCount()<=sceneAuthUserCount){
            result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.FULL.value);
            result.setTips(authSceneInfo.getFullUseTips());
            return result;
        }
        //新增一条校验成功记录
        addUserRecord(bookSceneAuthCode.getBookId(), channelId, bookSceneAuthCode.getAdviserId(), wechatUserId, useAuthCodeVO.getAuthBookType(),bookSceneAuthCode.getId(), bookSceneAuthCode.getSceneId());
        //修改使用人数
        bookSceneAuthCodeDao.updateUseCount(bookSceneAuthCode.getId());
        result.setCodeUseStatus(BookStatusEnum.CodeUseTypeEnum.RIGHT.value);
        return result;
    }

    private void addUserRecord(Long bookId, Long channelId, Long adviserId, Long wechatUserId, Integer authBookType,Long bookAuthCodeId, Long sceneId) {
        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);
        bookAuthUser.setSceneId(sceneId);
        bookAuthUser.setBookAuthType(2);
        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);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setBookCodeAuth(BookSceneAuth bookSceneAuth, Long adviserId) {
        if(ObjectUtil.hasEmpty(bookSceneAuth,bookSceneAuth.getBookId(),bookSceneAuth.getSceneId())){
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "缺少参数");
        }
        BookSceneAuth authSceneInfo = bookSceneAuthDao.getAuthSceneInfo(bookSceneAuth.getBookId(), bookSceneAuth.getSceneId());
        if(null==authSceneInfo){
            BookSceneAuth build = BookSceneAuth.builder().bookId(bookSceneAuth.getBookId()).adviserId(adviserId).channelId(bookSceneAuth.getChannelId()).sceneId(bookSceneAuth.getSceneId())
                    .maxUserCount(null!=bookSceneAuth.getMaxUserCount() ? bookSceneAuth.getMaxUserCount() : 2).fullUseTips(bookSceneAuth.getFullUseTips()).createdUser(adviserId).build();
            bookSceneAuthDao.insert(build);
        }else{
           authSceneInfo.setMaxUserCount(bookSceneAuth.getMaxUserCount());
           authSceneInfo.setFullUseTips(bookSceneAuth.getFullUseTips());
           bookSceneAuthDao.update(authSceneInfo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSceneAuthInfo(List<BookSceneAuth> list, Long adviserId) {
        if(CollUtil.isEmpty(list)){
            return;
        }
        Long bookId = list.get(0).getBookId();
        List<Long> sceneIds = list.stream().map(a -> a.getSceneId()).collect(Collectors.toList());
        List<BookSceneAuth> authSceneIds = bookSceneAuthDao.getAuthSceneIds(bookId, sceneIds);
        Map<Long, Long> authSceneMap =CollUtil.isEmpty(authSceneIds) ? new HashMap<>() : authSceneIds.stream().collect(Collectors.toMap(a -> a.getSceneId(), a -> a.getId(), (k1, k2) -> k2));
        List<BookSceneAuth> insertList=new ArrayList<>();
        List<BookSceneAuth> updateList=new ArrayList<>();
        for (BookSceneAuth bookSceneAuth : list) {
            bookSceneAuth.setAdviserId(adviserId);
            bookSceneAuth.setCreatedUser(adviserId);
            if(CollUtil.isNotEmpty(authSceneMap) && authSceneMap.containsKey(bookSceneAuth.getSceneId())){
                bookSceneAuth.setId(authSceneMap.get(bookSceneAuth.getSceneId()));
                updateList.add(bookSceneAuth);
            }else{
                insertList.add(bookSceneAuth);
            }
        }
        if(CollUtil.isNotEmpty(insertList)){
            bookSceneAuthDao.insert(insertList);
        }
        if(CollUtil.isNotEmpty(updateList)){
            bookSceneAuthDao.batchUpdate(updateList);
        }
    }

    @Override
    public List<SceneAuthCodeResponseDTO> getSceneAuthInfo(SceneAuthCodeSearchDTO dto) {
         if(ObjectUtil.hasEmpty(dto,dto.getBookId()) || CollUtil.isEmpty(dto.getSceneIds())){
             return null;
         }
        List<SceneAuthCodeResponseDTO> result=new ArrayList<>();
        List<BookSceneAuth> authSceneIds = bookSceneAuthDao.getAuthSceneIds(dto.getBookId(), dto.getSceneIds());
        Map<Long, BookSceneAuth> authMap = CollUtil.isEmpty(authSceneIds) ? new HashMap<>() : authSceneIds.stream().collect(Collectors.toMap(a -> a.getSceneId(), Function.identity(), (k1, k2) -> k2));
        List<SceneAuthCodeResponseDTO> codeCount = bookSceneAuthCodeDao.getCodeCount(dto.getBookId(), dto.getSceneIds());
        Map<Long, Integer> codeCountMap = CollUtil.isEmpty(codeCount) ? new HashMap<>() : codeCount.stream().collect(Collectors.toMap(a -> a.getSceneId(), a->a.getCounts(), (k1, k2) -> k2));

        SceneAuthCodeResponseDTO sceneAuthCodeResponseDTO;
        for (Long sceneId : dto.getSceneIds()) {
            sceneAuthCodeResponseDTO=new SceneAuthCodeResponseDTO();
            sceneAuthCodeResponseDTO.setSceneId(sceneId);
            if(CollUtil.isNotEmpty(authMap) && authMap.containsKey(sceneId)){
                BookSceneAuth bookSceneAuth = authMap.get(sceneId);
                if(null!=bookSceneAuth){
                    sceneAuthCodeResponseDTO.setFullUseTips(bookSceneAuth.getFullUseTips());
                    sceneAuthCodeResponseDTO.setMaxUserCount(bookSceneAuth.getMaxUserCount());
                }
            }
            if(CollUtil.isNotEmpty(codeCountMap) && codeCountMap.containsKey(sceneId)){
                sceneAuthCodeResponseDTO.setCounts(codeCountMap.get(sceneId));
            }
            result.add(sceneAuthCodeResponseDTO);
        }
        return result;
    }

    @Override
    public Map<String, Object> exportSceneAuthCode(Long bookId, String codeIds, Long channelId, Long sceneId,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, "授权码所对应的书不存在");
        }
        QrcodeSceneDto qrcodeSceneDto = qrcodeSceneConsr.getById(sceneId);
        if(null==qrcodeSceneDto){
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "授权码所对应的二维码不存在");
        }
        //表名
        String title = "《" + bookDto.getBookName() + "》" + qrcodeSceneDto.getSceneName()+"的授权码";
        String[] rowsName = {"序号", "完整授权码", "生成方式", "状态", "创建时间"};
        String fileUrl = "";
        String finalTitle = title;
        //不管是全部导出还是导出部分，都使用异步处理
        if (status == 0) {
            EXECUTOR_SERVICE.execute(() -> {
                String filePath = this.exportAllFreeCode(finalTitle, rowsName, bookId, channelId, partyId, authBookType,sceneId);
                //发送站内信
                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;
    }

    private String exportAllFreeCode(String title, String[] rowsName, Long bookId, Long channelId, Long partyId, Integer authBookType,Long sceneId) {
        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);
        }
        paramMap.put("sceneId",sceneId);
        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 = bookSceneAuthCodeDao.getBookSceneAuthCodeList(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 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;
    }

    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++) {
                BookSceneAuthCode bookAuthCode = bookSceneAuthCodeDao.getById(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] = (null!=bookAuthCode.getUseCount() &&  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;
    }

}