package org.agt.module.license.service.license;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.agt.framework.common.pojo.PageResult;
import org.agt.framework.common.util.object.BeanUtils;
import org.agt.framework.dict.core.DictFrameworkUtils;
import org.agt.framework.web.core.util.WebFrameworkUtils;
import org.agt.module.infra.api.file.FileApi;
import org.agt.module.license.controller.admin.license.vo.LicenseDetailVO;
import org.agt.module.license.controller.admin.license.vo.LicensePageReqVO;
import org.agt.module.license.controller.admin.license.vo.LicenseRespVO;
import org.agt.module.license.controller.admin.license.vo.LicenseSaveReqVO;
import org.agt.module.license.dal.dataobject.customer.CustomerDO;
import org.agt.module.license.dal.dataobject.license.LicenseDO;
import org.agt.module.license.dal.dataobject.license.LicenseDetailDO;
import org.agt.module.license.dal.dataobject.license.LicenseDetailHistoryDO;
import org.agt.module.license.dal.dataobject.license.LicenseHistoryDO;
import org.agt.module.license.dal.dataobject.license.LicenseProviderDO;
import org.agt.module.license.dal.dataobject.project.ProjectDO;
import org.agt.module.license.dal.mysql.customer.CustomerMapper;
import org.agt.module.license.dal.mysql.license.LicenseDetailHistoryMapper;
import org.agt.module.license.dal.mysql.license.LicenseDetailMapper;
import org.agt.module.license.dal.mysql.license.LicenseHistoryMapper;
import org.agt.module.license.dal.mysql.license.LicenseMapper;
import org.agt.module.license.dal.mysql.license.LicenseProviderMapper;
import org.agt.module.license.dal.mysql.project.ProjectMapper;
import org.agt.module.license.enums.LicenseStatusEnum;
import org.agt.module.system.api.mail.MailSendApi;
import org.agt.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import org.agt.module.system.api.notify.NotifyMessageSendApi;
import org.agt.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static org.agt.framework.common.exception.util.ServiceExceptionUtil.exception;
import static org.agt.module.license.enums.ErrorCodeConstants.LICENSE_NOT_EXISTS;
import static org.agt.module.license.enums.ErrorCodeConstants.LICENSE_SN_DUPLICATE;

/**
 * License Service 实现类
 *
 * @author 管理员
 */
@Slf4j
@Service
@Validated
public class LicenseServiceImpl implements LicenseService {

    @Resource
    private LicenseMapper licenseMapper;

    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private LicenseProviderMapper licenseProviderMapper;

    @Resource
    private FileApi fileApi;

    @Resource
    private MailSendApi mailSendApi;

    @Resource
    private NotifyMessageSendApi notifySendApi;

    @Resource
    private LicenseDetailMapper licenseDetailMapper;

    @Resource
    private LicenseHistoryMapper licenseHistoryMapper;

    @Resource
    private LicenseDetailHistoryMapper licenseDetailHistoryMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createLicense(LicenseSaveReqVO createReqVO, boolean isReapply) {
        // 校验项目Sn是否唯一, boolean isReapply
        if (!validateLicenseSnUnique(createReqVO.getSerialNo(), createReqVO.getId())) {
            throw exception(LICENSE_SN_DUPLICATE, createReqVO.getSerialNo());
        }

        if (createReqVO.getExpiryDate() != null) {
            createReqVO.setExpiryDate(LocalDateTime.of(createReqVO.getExpiryDate().toLocalDate(), LocalTime.of(23, 59, 59)));
        }
        // 插入
        LicenseDO license = BeanUtils.toBean(createReqVO, LicenseDO.class);
        license.setStatus(LicenseStatusEnum.NOT_APPLIED.getCode());
        if (isReapply) {
            licenseMapper.update(Wrappers.<LicenseDO>lambdaUpdate()
                    .eq(LicenseDO::getId, license.getId())
                    .set(LicenseDO::getExpiryDate, license.getExpiryDate())
                    .set(LicenseDO::getUserNumber, license.getUserNumber())
                    .set(LicenseDO::getRanNumber, license.getRanNumber())
                    .set(LicenseDO::getRemark, StrUtil.isBlank(license.getRemark()) ? null : license.getRemark())
                    .set(LicenseDO::getApprover, license.getApprover())
                    .set(LicenseDO::getFileUrl, null)
            );
        } else {
            licenseMapper.insert(license);
        }

        List<LicenseDetailVO> neCodeList = createReqVO.getNeCodeList();

        List<LicenseDetailDO> licenseDetails = BeanUtils.toBean(neCodeList, LicenseDetailDO.class);
        for (LicenseDetailDO licenseDetail : licenseDetails) {
            licenseDetail.setLicenseId(license.getId());
        }
        licenseDetailMapper.insertBatch(licenseDetails);

        createReqVO.setId(license.getId());
        applyLicense(createReqVO, licenseDetails);
        // 返回
        return license.getId();
    }

    @Override
    public void updateLicense(LicenseSaveReqVO updateReqVO) {
        // 校验项目Sn是否唯一
        if (!validateLicenseSnUnique(updateReqVO.getSerialNo(), updateReqVO.getId())) {
            throw exception(LICENSE_SN_DUPLICATE, updateReqVO.getSerialNo());
        }
        // 校验存在
        validateLicenseExists(updateReqVO.getId());
        if (updateReqVO.getExpiryDate() != null) {
            updateReqVO.setExpiryDate(LocalDateTime.of(updateReqVO.getExpiryDate().toLocalDate(), LocalTime.of(23, 59, 59)));
        }
        // 更新
        LicenseDO updateObj = BeanUtils.toBean(updateReqVO, LicenseDO.class);
        licenseMapper.updateById(updateObj);
    }

    @Override
    public void applyLicense(LicenseSaveReqVO updateReqVO, List<LicenseDetailDO> licenseDetails) {
        // 发送邮件
        // 1. 准备参数
        Long userId = updateReqVO.getApprover();
        String templateCode = "license_apply"; // 邮件模版，记得在【邮箱管理】中配置噢
        Map<String, Object> templateParams = new HashMap<>();
        CustomerDO customerDO = customerMapper.selectById(updateReqVO.getCustomerId());
        ProjectDO projectDO = projectMapper.selectById(updateReqVO.getProjectId());
        templateParams.put("customer", customerDO.getName());
        templateParams.put("project", projectDO.getName());
        templateParams.put("sn", updateReqVO.getSerialNo());
        templateParams.put("url", "http://192.168.9.50#/license/generate?id=" + updateReqVO.getId());

        // 2. 发送邮件
        mailSendApi.sendSingleMailToAdmin(new MailSendSingleToUserReqDTO()
                .setUserId(userId).setTemplateCode(templateCode).setTemplateParams(templateParams));

        // 发送站内信
        notifySendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
                .setUserId(userId).setTemplateCode(templateCode).setTemplateParams(templateParams));

//        List<LicenseNeCodeVO> neCodeList = updateReqVO.getNeCodeList();

        for (LicenseDetailDO neCodeVO : licenseDetails) {
            // 添加数据到License提供者表
            LicenseProviderDO licenseProviderDO = new LicenseProviderDO();
            licenseProviderDO.setCustomerId(updateReqVO.getCustomerId());
            licenseProviderDO.setProjectId(updateReqVO.getProjectId());
            licenseProviderDO.setSerialNo(updateReqVO.getSerialNo());
            licenseProviderDO.setExpiryDate(updateReqVO.getExpiryDate());
            licenseProviderDO.setRanNumber(updateReqVO.getRanNumber());
            licenseProviderDO.setUserNumber(updateReqVO.getUserNumber());
            List<Integer> neList = neCodeVO.getNeList();
            List<String> neLabels = new ArrayList<>();
            for (Integer ne : neList) {
                String label = DictFrameworkUtils.parseDictDataLabel("lic_ne_all", ne.toString());
                if (StrUtil.isBlank(label)) {
                    label = DictFrameworkUtils.parseDictDataLabel("lic_ne_5g", ne.toString());
                    if (StrUtil.isBlank(label)) {
                        label = DictFrameworkUtils.parseDictDataLabel("lic_ne_4g", ne.toString());
                        if (StrUtil.isBlank(label)) {
                            label = DictFrameworkUtils.parseDictDataLabel("lic_ne_23g", ne.toString());
                            if (StrUtil.isBlank(label)) {
                                label = DictFrameworkUtils.parseDictDataLabel("lic_ne_add", ne.toString());
                            }
                        }
                    }
                }
                neLabels.add(label);
            }
            licenseProviderDO.setNeList(StrUtil.join(",", neLabels));
            licenseProviderDO.setActivationCode(neCodeVO.getActivationCode());
            licenseProviderDO.setOperationType(1);
            licenseProviderDO.setState(1);
            licenseProviderDO.setRemark(updateReqVO.getRemark());
            licenseProviderDO.setApprover(updateReqVO.getApprover());

            licenseProviderMapper.insert(licenseProviderDO);
            neCodeVO.setProviderId(licenseProviderDO.getId());
        }

        licenseDetailMapper.updateBatch(licenseDetails);

        // 更新表
        LicenseDO licenseDO = new LicenseDO();
        licenseDO.setId(updateReqVO.getId());
        licenseDO.setStatus(LicenseStatusEnum.IN_APPLICATION.getCode());
        licenseDO.setApplicant(WebFrameworkUtils.getLoginUserId());
        licenseDO.setApplicationTime(LocalDateTime.now());
        licenseMapper.updateById(licenseDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reapplyLicense(LicenseSaveReqVO updateReqVO) {
        // 校验存在
        validateLicenseExists(updateReqVO.getId());
        // 将现有的license迁移到历史表
        LicenseDO licenseDO = licenseMapper.selectById(updateReqVO.getId());
        List<LicenseDetailDO> licenseDetailDOS = licenseDetailMapper.selectList(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, licenseDO.getId()));

        LicenseHistoryDO historyDO = BeanUtils.toBean(licenseDO, LicenseHistoryDO.class);

        licenseDetailMapper.delete(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, licenseDO.getId()));

        for (LicenseDetailVO neCode : updateReqVO.getNeCodeList()) {
            neCode.setFileUrlLegacy(null);
            neCode.setFileUrl(null);
            neCode.setProviderId(null);
        }
        Long licenseId = createLicense(updateReqVO, true);
        historyDO.setId(null);
        historyDO.setLicenseId(licenseId);
        licenseHistoryMapper.insert(historyDO);

        if (CollUtil.isNotEmpty(licenseDetailDOS)) {
            List<LicenseDetailHistoryDO> detailHistoryDOList = BeanUtils.toBean(licenseDetailDOS, LicenseDetailHistoryDO.class);
            detailHistoryDOList.forEach(c -> {
                c.setId(null);
                c.setLicenseId(historyDO.getId());
            });
            licenseDetailHistoryMapper.insertBatch(detailHistoryDOList);
        }
        licenseMapper.updateById(new LicenseDO().setId(licenseId).setStatus(LicenseStatusEnum.REAPPLYING.getCode()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generate(Long id) {
        LicenseDO licenseDO = licenseMapper.selectById(id);

        List<LicenseDetailDO> licenseDetailDOS = licenseDetailMapper.selectList(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, licenseDO.getId()));

        for (LicenseDetailDO neCodeVO : licenseDetailDOS) {
            LicenseProviderDO licenseProviderDO = licenseProviderMapper.selectById(neCodeVO.getProviderId());
            licenseProviderDO.setState(2);
            licenseProviderMapper.updateById(licenseProviderDO);
        }

        licenseDO.setStatus(LicenseStatusEnum.GENERATING.getCode());
        licenseMapper.updateById(licenseDO);
        return "";
    }

    public void genLicenseTask() {
        List<LicenseDO> licenses = licenseMapper.selectList(Wrappers.<LicenseDO>lambdaQuery().eq(LicenseDO::getStatus, LicenseStatusEnum.GENERATING.getCode()));
        for (LicenseDO licenseDO : licenses) {
            List<LicenseDetailDO> licenseDetails = licenseDetailMapper.selectList(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, licenseDO.getId()));

            for (LicenseDetailDO detail : licenseDetails) {
                if (StrUtil.isNotBlank(detail.getFileUrl()) && StrUtil.isNotBlank(detail.getFileUrlLegacy())) {
                    continue;
                }
                LicenseProviderDO licenseProviderDO = licenseProviderMapper.selectById(detail.getProviderId());
                if (licenseProviderDO == null || licenseProviderDO.getState() != 3) {
                    continue;
                }

                String fileName = getFileName(licenseDO.getSerialNo(), detail.getNeList());

                List<String> fileUrls = new ArrayList<>();
                String newFilePath1 = licenseProviderDO.getNewFilePath1();
                if (StrUtil.isNotBlank(newFilePath1)) {
                    byte[] fileContent = null;
                    try {
                        log.info("下载License文件路径为：{}", newFilePath1);
                        fileContent = FileUtil.readBytes(newFilePath1);
                    } catch (Exception e) {
                        log.error("读取文件失败", e);
                    }
                    if (fileContent == null) {
                        log.error("读取文件失败为空");
//                        fileContent = ResourceUtil.readBytes("file/MME_13750602_2024-08-02_system.ini");
                    } else {
                        // 上传到文件服务
                        String preFileName = "45G_";
                        if (newFilePath1.contains("Legacy_")) {
                            preFileName = "Legacy_";
                        }
                        String fileURL = fileApi.createFile(fileContent, preFileName + fileName);
                        fileUrls.add(fileURL);
                    }

                }

                String newFilePath0 = licenseProviderDO.getNewFilePath0();
                if (StrUtil.isNotBlank(newFilePath0)) {
                    byte[] fileContent0 = null;
                    try {
                        log.info("下载Legacy_License文件路径为：{}", newFilePath0);
                        fileContent0 = FileUtil.readBytes(newFilePath0);
                    } catch (Exception e) {
                        log.error("读取文件失败", e);
                    }
                    if (fileContent0 == null) {
                        log.error("读取文件失败为空");
//                        fileContent0 = ResourceUtil.readBytes("file/MME_13750602_2024-08-02_system.ini");
                    } else {
                        // 上传到文件服务
                        String preFileName = "45G_";
                        if (newFilePath0.contains("Legacy_")) {
                            preFileName = "Legacy_";
                        }
                        String fileURL = fileApi.createFile(fileContent0, preFileName + fileName);
                        fileUrls.add(fileURL);
                    }

                }

                if (CollUtil.isEmpty(fileUrls)) {
                    byte[] fileContent = ResourceUtil.readBytes("file/MME_13750602_2024-08-02_system.ini");
                    String fileURL = fileApi.createFile(fileContent, fileName);
                    fileUrls.add(fileURL);
                }

                if (CollUtil.isNotEmpty(fileUrls)) {
                    detail.setFileUrl(fileUrls.get(0));
                }
                if (CollUtil.isNotEmpty(fileUrls) && fileUrls.size() > 1) {
                    detail.setFileUrlLegacy(fileUrls.get(1));
                }
                licenseDetailMapper.updateById(detail);
            }

            boolean isCompleted = licenseDetails.stream().allMatch(c -> StrUtil.isNotBlank(c.getFileUrl()));

            if (isCompleted && CollUtil.isNotEmpty(licenseDetails)) {
                // 打包压缩上传
                List<String> pathList = new ArrayList<>();
                List<ByteArrayInputStream> inputStreamList = new ArrayList<>();
                for (LicenseDetailDO detail : licenseDetails) {
                    LicenseProviderDO licenseProviderDO = licenseProviderMapper.selectById(detail.getProviderId());
                    String fileName = getFileName(licenseDO.getSerialNo(), detail.getNeList());
                    if (StrUtil.isNotBlank(licenseProviderDO.getNewFilePath1())) {
                        String preFileName = "45G_";
                        if (licenseProviderDO.getNewFilePath1().contains("Legacy_")) {
                            preFileName = "Legacy_";
                        }
                        pathList.add(preFileName + fileName);
                        inputStreamList.add(new ByteArrayInputStream(FileUtil.readBytes(licenseProviderDO.getNewFilePath1())));
                    }
                    if (StrUtil.isNotBlank(licenseProviderDO.getNewFilePath0())) {
                        String preFileName = "45G_";
                        if (licenseProviderDO.getNewFilePath0().contains("Legacy_")) {
                            preFileName = "Legacy_";
                        }
                        pathList.add(preFileName + fileName);
                        inputStreamList.add(new ByteArrayInputStream(FileUtil.readBytes(licenseProviderDO.getNewFilePath0())));
                    }

                    if (StrUtil.isBlank(licenseProviderDO.getNewFilePath0()) && StrUtil.isBlank(licenseProviderDO.getNewFilePath1())) {
                        pathList.add(fileName);
                        inputStreamList.add(new ByteArrayInputStream(ResourceUtil.readBytes("file/MME_13750602_2024-08-02_system.ini")));
                    }
                }

//                File tempFile = new File("D:/temp/temp.zip");
                File tempFile = new File("/usr/local/licGen/temp.zip");
                ZipUtil.zip(tempFile, pathList.toArray(new String[0]), inputStreamList.toArray(new ByteArrayInputStream[inputStreamList.size()]));
                String fileURL = fileApi.createFile(FileUtil.readBytes(tempFile), licenseDO.getSerialNo() + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + ".zip");

                FileUtil.del(tempFile);
                licenseDO.setFileUrl(fileURL);
                licenseDO.setStatus(LicenseStatusEnum.COMPLETED.getCode());
                licenseMapper.updateById(licenseDO);
            }

        }

    }

    private static String getFileName(String serialNo, List<Integer> neList) {
        List<String> neLabels = new ArrayList<>();
        for (Integer ne : neList) {
            String label = DictFrameworkUtils.parseDictDataLabel("lic_ne_all", ne.toString());
            if (StrUtil.isBlank(label)) {
                label = DictFrameworkUtils.parseDictDataLabel("lic_ne_5g", ne.toString());
                if (StrUtil.isBlank(label)) {
                    label = DictFrameworkUtils.parseDictDataLabel("lic_ne_4g", ne.toString());
                    if (StrUtil.isBlank(label)) {
                        label = DictFrameworkUtils.parseDictDataLabel("lic_ne_23g", ne.toString());
                        if (StrUtil.isBlank(label)) {
                            label = DictFrameworkUtils.parseDictDataLabel("lic_ne_add", ne.toString());
                        }
                    }
                }
            }
            neLabels.add(label);
        }
        String neListStr = StrUtil.join("_", neLabels);
        if (StrUtil.isNotBlank(neListStr)) {
            neListStr = neListStr + "_";
        }
        return neListStr + serialNo + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "_system.ini";
    }

    @Override
    public void deleteLicense(Long id) {
        // 校验存在
        validateLicenseExists(id);
        // 删除
        licenseMapper.deleteById(id);

        licenseDetailMapper.delete(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, id));

        List<LicenseHistoryDO> licenseHistoryDOS = licenseHistoryMapper.selectList(Wrappers.<LicenseHistoryDO>lambdaQuery().eq(LicenseHistoryDO::getLicenseId, id));
        for (LicenseHistoryDO licenseHistoryDO : licenseHistoryDOS) {
            licenseDetailHistoryMapper.delete(Wrappers.<LicenseDetailHistoryDO>lambdaQuery().eq(LicenseDetailHistoryDO::getLicenseId, licenseHistoryDO.getId()));
        }
        licenseHistoryMapper.delete(Wrappers.<LicenseHistoryDO>lambdaQuery().eq(LicenseHistoryDO::getLicenseId, id));

    }

    private void validateLicenseExists(Long id) {
        if (licenseMapper.selectById(id) == null) {
            throw exception(LICENSE_NOT_EXISTS);
        }
    }

    @Override
    public LicenseRespVO getLicense(Long id) {
        LicenseDO licenseDO = licenseMapper.selectById(id);
        LicenseRespVO licenseRespVO = BeanUtils.toBean(licenseDO, LicenseRespVO.class);
        fillLicenseRespVO(licenseRespVO);
        return licenseRespVO;
    }

    private void fillLicenseRespVO(LicenseRespVO license) {
        List<LicenseDetailDO> licenseDetailDOS = licenseDetailMapper.selectList(Wrappers.<LicenseDetailDO>lambdaQuery().eq(LicenseDetailDO::getLicenseId, license.getId()));
        List<LicenseDetailVO> details = BeanUtils.toBean(licenseDetailDOS, LicenseDetailVO.class);
        fillDetail(details, license);
        List<LicenseHistoryDO> historyList = licenseHistoryMapper.selectList(Wrappers.<LicenseHistoryDO>lambdaQuery()
                .eq(LicenseHistoryDO::getLicenseId, license.getId())
                .orderByDesc(LicenseHistoryDO::getApplicationTime));
        Optional<LicenseHistoryDO> histroyOptional = historyList.stream().findFirst();
        license.setHasHistory(histroyOptional.isPresent());
        if (LicenseStatusEnum.REAPPLYING.getCode().equals(license.getStatus())) {
            if (histroyOptional.isPresent()) {
                LicenseHistoryDO historyDO = histroyOptional.get();
                LicenseRespVO oldLicense = BeanUtils.toBean(historyDO, LicenseRespVO.class);

                List<LicenseDetailHistoryDO> oldDetailDOS = licenseDetailHistoryMapper.selectList(Wrappers.<LicenseDetailHistoryDO>lambdaQuery().eq(LicenseDetailHistoryDO::getLicenseId, oldLicense.getId()));
                List<LicenseDetailVO> oldDetails = BeanUtils.toBean(oldDetailDOS, LicenseDetailVO.class);
                fillDetail(oldDetails, oldLicense);

                license.setOldLicense(oldLicense);

                int maxLength = oldDetails.size();
                if (oldDetails.size() < details.size()) {
                    maxLength = details.size();
                }

                List<LicenseDetailVO> mergeDetails = new ArrayList<>();
                for (int i = 0; i < maxLength; i++) {
                    Map<String, String> activationCodeMap = new HashMap<>();
                    Map<String, List<Integer>> neListMap = new HashMap<>();
                    Map<String, List<String>> fileUrlListMap = new HashMap<>();

                    LicenseDetailVO mergeDetail = new LicenseDetailVO();
                    if (i < oldDetails.size()) {
                        activationCodeMap.put("old", oldDetails.get(i).getActivationCode());
                        neListMap.put("old", oldDetails.get(i).getNeList());
                        fileUrlListMap.put("old", null);
                        mergeDetail.setFileUrl(oldDetails.get(i).getFileUrl());
                        mergeDetail.setNeList(oldDetails.get(i).getNeList());
                        mergeDetail.setActivationCode(oldDetails.get(i).getActivationCode());
                        mergeDetail.setFileUrlList(oldDetails.get(i).getFileUrlList());
                    }

                    if (i < details.size()) {
                        if (!(i < oldDetails.size() && Objects.equals(oldDetails.get(i).getActivationCode(), details.get(i).getActivationCode()))) {
                            activationCodeMap.put("new", details.get(i).getActivationCode());
                        }
                        if (!(i < oldDetails.size() && Objects.equals(oldDetails.get(i).getNeList(), details.get(i).getNeList()))) {
                            neListMap.put("new", details.get(i).getNeList());
                        }
                        if (!(i < oldDetails.size() && Objects.equals(oldDetails.get(i).getFileUrlList(), details.get(i).getFileUrlList()))) {
                            fileUrlListMap.put("new", null);
                        }
                    }
                    mergeDetail.setActivationCodeMap(activationCodeMap);
                    mergeDetail.setNeListMap(neListMap);
                    mergeDetail.setFileUrlListMap(fileUrlListMap);
                    mergeDetails.add(mergeDetail);
                }
                license.setNeCodeList(mergeDetails);
            }
        }

    }

    private void fillDetail(List<LicenseDetailVO> details, LicenseRespVO licenseRespVO) {
        for (LicenseDetailVO detail : details) {
            List<String> fileUrlList = new ArrayList<>();
            if (StrUtil.isNotBlank(detail.getFileUrl())) {
                fileUrlList.add(detail.getFileUrl());
            }
            if (StrUtil.isNotBlank(detail.getFileUrlLegacy())) {
                fileUrlList.add(detail.getFileUrlLegacy());
            }
            detail.setFileUrlList(fileUrlList);

            Map<String, String> activationCodeMap = new HashMap<>();
            activationCodeMap.put("old", detail.getActivationCode());
            detail.setActivationCodeMap(activationCodeMap);

            Map<String, List<Integer>> neListMap = new HashMap<>();
            neListMap.put("old", detail.getNeList());
            detail.setNeListMap(neListMap);

            Map<String, List<String>> fileUrlListMap = new HashMap<>();
            fileUrlListMap.put("old", detail.getFileUrlList());
            detail.setFileUrlListMap(fileUrlListMap);
        }
        licenseRespVO.setNeCodeList(details);
    }

    @Override
    public PageResult<LicenseRespVO> getLicensePage(LicensePageReqVO pageReqVO) {
        PageResult<LicenseDO> pageResult = licenseMapper.selectPage(pageReqVO);
        PageResult<LicenseRespVO> voPageResult = BeanUtils.toBean(pageResult, LicenseRespVO.class);
        for (LicenseRespVO licenseRespVO : voPageResult.getList()) {
            fillLicenseRespVO(licenseRespVO);
        }
        return voPageResult;
    }

    @Override
    public Boolean validateLicenseSnUnique(String sn, Long id) {
        if (StrUtil.isBlank(sn)) {
            return true;
        }
        LicenseDO license = licenseMapper.selectBySn(sn);
        if (license == null) {
            return true;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的License
        if (id == null) {
            return false;
        }
        if (!license.getId().equals(id)) {
            return false;
        }
        return true;
    }

    @Override
    public List<LicenseRespVO> getLicenseHistory(Long id) {
        List<LicenseHistoryDO> historyDOList = licenseHistoryMapper.selectList(Wrappers.<LicenseHistoryDO>lambdaQuery()
                .eq(LicenseHistoryDO::getLicenseId, id).orderByDesc(LicenseHistoryDO::getApplicationTime));
        List<LicenseRespVO> voList = BeanUtils.toBean(historyDOList, LicenseRespVO.class);
        for (LicenseRespVO licenseRespVO : voList) {
            fillLicenseHistoryRespVO(licenseRespVO);
        }
        return voList;
    }

    private void fillLicenseHistoryRespVO(LicenseRespVO license) {
        List<LicenseDetailHistoryDO> licenseDetailDOS = licenseDetailHistoryMapper.selectList(Wrappers.<LicenseDetailHistoryDO>lambdaQuery().eq(LicenseDetailHistoryDO::getLicenseId, license.getId()));
        List<LicenseDetailVO> details = BeanUtils.toBean(licenseDetailDOS, LicenseDetailVO.class);
        fillDetail(details, license);

    }
}