package com.hdkj.lt.job.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hdkj.hussar.ApiResponse;
import com.hdkj.hussar.ResultCode;
import com.hdkj.lt.base.constants.RocketMQConstants;
import com.hdkj.lt.base.constants.SymbolConstants;
import com.hdkj.lt.core.mq.client.RocketMQTemplate;
import com.hdkj.lt.core.mq.config.RocketMQProperties;
import com.hdkj.lt.core.mq.model.RocketMQMessageEntity;
import com.hdkj.lt.feign.IFileApiClient;
import com.hdkj.lt.job.entity.po.FhzgDistMappingFilePO;
import com.hdkj.lt.job.mapper.DistOSSSvgFileMapper;
import com.hdkj.lt.job.service.IDistOSSSvgFileService;
import com.hdkj.lt.job.util.JobUtils;
import com.hdkj.lt.modle.FileInfoDTO;
import com.hdkj.lt.modle.FileRequest;
import com.hdkj.lt.modle.FileUploadDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

import static cn.hutool.core.date.DatePattern.PURE_DATE_PATTERN;

/**
 * @Description
 * @Author wcx
 * @Date 2025/6/19 15:54
 * @Version 1.0
 */
@Service
@RefreshScope
@RequiredArgsConstructor
public class DistOSSSvgFileServiceImpl implements IDistOSSSvgFileService {

    private final IFileApiClient fileApiClient;
    private final DistOSSSvgFileMapper distOSSSvgFileMapper;
    private final RocketMQProperties rocketMQProperties;
    private final RocketMQTemplate rocketMQTemplate;

    @Value("${lt.custom-storage:false}")
    private Boolean customStorage; // 配电云主站定制化存储，默认不需要定制化，设置true表示开启
    @Value("${lt.file.max-size:100}")
    private Integer maxFileSize;

    @Override
    public void getAndSaveFileInfo(String fileDir) {
        this.saveDistMasterStationFile(fileDir);
    }

    @Override
    public void saveBatchFileInfo(String fileDir) {
        List<FileUploadDTO> fileData = this.saveDistMasterStationFile(fileDir);
        if (ObjectUtils.isNotEmpty(fileData)) {
            List<String> lineIds = new ArrayList<>();
            // 1.获取还需上传的异动文件信息
            List<String> fileNameList = distOSSSvgFileMapper.getDistMasterStationFile(maxFileSize);
            fileNameList.forEach(fileName -> {
                String updateFileName = fileName.substring(fileName.lastIndexOf(SymbolConstants.FORWARD_SLASH) + 1);
                // 2.获取单个下载文件
                byte[] fileByte = fileApiClient.getObject(fileName).getData();
                if (ObjectUtils.isNotEmpty(fileByte)) {
                    // 转换内容成svg
                    String fileContent = this.decodeBase64AndZipData(fileByte);
                    FileRequest fileRequest = FileRequest.builder().fileName(updateFileName).fileContent(fileContent).build();
                    // 3.上传文件到本地oss
                    FileInfoDTO fileInfo = fileApiClient.upload(fileRequest).getData();
                    lineIds.add(fileInfo.getOriginName().substring(0, fileInfo.getOriginName().lastIndexOf(".")));
                    // 4.处理需要保存的上传文件信息
                    this.dealDistMappingFile(fileInfo);

                    /*// 5.删除源文件信息，先上传保存数据后再处理源文件防止异常后丢失源文件
                    fileApiClient.removeObject(fileName);*/
                }
                fileByte = null; // 快速回收可能站内存的byte数组
            });
            // 5.改成不删除异动文件，逻辑删除上传文件信息
            Optional.ofNullable(fileNameList).filter(ObjectUtils::isNotEmpty)
                    .ifPresent(e -> distOSSSvgFileMapper.updateDistMasterStationFile(e));
            // 当发现.txt文件,且异动文件已经上传完成时, 需要修改配置数据和mq消息订阅
            List<FileUploadDTO> txtFile = fileData.stream().filter(e -> e.getFileName().endsWith(".txt"))
                    .sorted(Comparator.comparing(FileUploadDTO::getUploadTime)).collect(Collectors.toList());
            if (ObjectUtils.isNotEmpty(txtFile) && ObjectUtils.isEmpty(fileNameList)) {
                // 删除配电云主站异动文件上传完成标识的.txt文件，同-配置时间段内只保留一个txt文件
                txtFile.stream().limit(Math.max(0, txtFile.size() - 1)).forEach(e -> fileApiClient.removeObject(e.getFileName()));
                LocalDateTime currentTime = LocalDateTime.now();// 当前时间
                distOSSSvgFileMapper.updateConfigFileChangeTime(currentTime, currentTime.plusDays(1L));
                // 解析TOPO数据的MQ消息订阅
                this.sendRocketMQMessage(lineIds);
            }
        }
    }

    /**
     * 保存配电云主站获取的文件信息
     */
    private List<FileUploadDTO> saveDistMasterStationFile(String fileDir) {
        String configValue = distOSSSvgFileMapper.getConfigValueFileChange();
        // 当配置值为0时, 表示当前上传任务未执行完成
        if (LocalDate.now().compareTo(LocalDate.parse(configValue)) >= 0) {
            // 获取全量异动文件，根据异动文件上传时间来确定是否更新数据
            ApiResponse<List<FileUploadDTO>> harmony = fileApiClient.listObject(fileDir);
            if (harmony.getCode() == ResultCode.SUCCESS.getCode()) {
                List<FileUploadDTO> fileData = harmony.getData();
                // 处理更换需要上传的最新的异动文件并保存文件记录
                this.dealDistMasterStationFile(fileData);
                return fileData;
            }
        }
        return Lists.newArrayList();
    }

    /**
     * 处理需要上传的配电云主站异动文件
     */
    private void dealDistMasterStationFile(List<FileUploadDTO> fileData) {
        // 定制化后的需要上传文件集合
        List<FileUploadDTO> fileNameList = Lists.newArrayList();
        // 定制化存储时，查询配置地市的线路信息
        List<String> lineIdList = Lists.newArrayList();
        if (customStorage) {
            lineIdList.addAll(Optional.ofNullable(distOSSSvgFileMapper.getCustomStorageLine()).orElse(lineIdList));
        }
        // 定制化逻辑筛选文件
        fileData.forEach(file -> {
            String updateFileName = file.getFileName().substring(file.getFileName().lastIndexOf(SymbolConstants.FORWARD_SLASH) + 1);
            // 执行上传文件的标识, 和定制化配置值相反（开启定制化后，需要根据配置信息来判断是否上传）
            Boolean uploadFlag = !customStorage;
            // 配电云主站自定义开启时，判断文件是否需要上传
            if (customStorage && ObjectUtils.isNotEmpty(lineIdList)) {
                // 根据文件名截取线路ID
                String lineId = updateFileName.substring(0, updateFileName.lastIndexOf("."));
                uploadFlag = lineIdList.contains(lineId); // 重新设置自定义上传标识
            }
            if (uploadFlag) {
                fileNameList.add(file);
            }
        });
        // 获取配电已知的全量异动文件
        Map<String, FileUploadDTO> uploadFileMap = Optional.ofNullable(distOSSSvgFileMapper.getAllDistMasterStationFile())
                .map(e -> e.stream().collect(Collectors.toMap(en -> en.getFileName(), en -> en))).orElse(MapUtil.newHashMap());
        // 云主站需要补充删除的文件信息
        List<String> deleteHarmonyFile = Optional.ofNullable(fileNameList)
                .map(e -> e.stream().filter(en -> !en.getFileName().endsWith(".txt"))
                        .filter(en -> ObjectUtils.isNotEmpty(uploadFileMap.get(en.getFileName()))
                                && en.getUploadTime().isAfter(uploadFileMap.get(en.getFileName()).getUploadTime()))
                        .map(FileUploadDTO::getFileName).collect(Collectors.toList()))
                .orElse(Lists.newArrayList());
        // 配电云主站需要补充的文件信息
        List<FileUploadDTO> harmonyFile = Optional.ofNullable(fileNameList)
                .map(e -> e.stream().filter(en -> !en.getFileName().endsWith(".txt"))
                        .filter(en -> !(ObjectUtils.isNotEmpty(uploadFileMap.get(en.getFileName()))
                                && en.getUploadTime().compareTo(uploadFileMap.get(en.getFileName()).getUploadTime()) <= 0))
                        .collect(Collectors.toList()))
                .orElse(Lists.newArrayList());
        // 先逻辑删除文件，在增加最新的需要上传的文件
        Optional.ofNullable(deleteHarmonyFile).filter(ObjectUtils::isNotEmpty)
                .ifPresent(e -> JobUtils.saveBatchData(e, 2000, en -> this.updateDistMasterStationFile(en)));
        Optional.ofNullable(harmonyFile).filter(ObjectUtils::isNotEmpty)
                .ifPresent(e -> JobUtils.saveBatchData(e, 2000, en -> this.insertDistMasterStationFile(en)));
    }

    /**
     * 处理业务数据信息
     */
    private void dealDistMappingFile(FileInfoDTO fileInfo) {
        // 线路ID来源文件名
        String lineId = fileInfo.getOriginName().substring(0, fileInfo.getOriginName().lastIndexOf("."));
        // 文件类型来源文件名后缀
        String fileType = (StringUtils.equals(fileInfo.getSuffix(), "svg") ? "1" : "2");

        // 删除线路附件映射表文件信息
        LambdaUpdateWrapper<FhzgDistMappingFilePO> deleteWrapper = new LambdaUpdateWrapper<FhzgDistMappingFilePO>()
                .eq(FhzgDistMappingFilePO::getLineId, lineId)
                .eq(FhzgDistMappingFilePO::getFileType, fileType);
        distOSSSvgFileMapper.delete(deleteWrapper);

        // 新增线路附件映射表文件信息
        FhzgDistMappingFilePO distMappingFile = new FhzgDistMappingFilePO();
        distMappingFile.setFileId(Long.valueOf(fileInfo.getId()))
                .setLineId(lineId).setFileType(fileType)
                .setTopoVersion(LocalDate.now().format(DateTimeFormatter.ofPattern(PURE_DATE_PATTERN)))
                .setCreateTime(LocalDateTime.now());
        distOSSSvgFileMapper.insert(distMappingFile);
    }

    /**
     * 修改配电云主站已处理文件
     */
    private Boolean updateDistMasterStationFile(List<String> fileNameList) {
        distOSSSvgFileMapper.updateDistMasterStationFile(fileNameList);
        return Boolean.TRUE;
    }

    /**
     * 新增配电云主站需要处理文件
     */
    private Boolean insertDistMasterStationFile(List<FileUploadDTO> fileList) {
        distOSSSvgFileMapper.insertDistMasterStationFile(fileList, LocalDateTime.now());
        return Boolean.TRUE;
    }

    /**
     * 解析文件base64+zip的文件转换成文件内容
     */
    private String decodeBase64AndZipData(byte[] fileByte) {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(fileByte));
             ZipInputStream zis = new ZipInputStream(bais);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            // ZIP解压（根据现有信息假设只有一个文件）
            zis.getNextEntry(); //定位到压缩包中的第一个文件

            // 读取解压后的数据
            byte[] buffer = new byte[1024];
            int len;
            while ((len = zis.read(buffer)) > 0) {
                baos.write(buffer, 0, len);
            }

            // 字节转字符串（默认UTF-8）
            String fileContent = new String(baos.toByteArray(), StandardCharsets.UTF_8);
            return fileContent;
        } catch (Exception ex) {
            ex.printStackTrace();
            return new String(fileByte, StandardCharsets.UTF_8);
        }
    }


    /**
     * 解析TOPO数据的MQ消息订阅
     */
    private void sendRocketMQMessage(List<String> lineIds) {
        try {
            // MQ消息订阅，当触发消息发送失败时不影响接口功能
            if (rocketMQProperties.getEnabled()) {
                RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
                        .topicId(RocketMQConstants.TOPIC_ID_DO_CITY_FEEDER_TOPO_TICKET)
                        .cacheKey(RocketMQConstants.TOPIC_ID_DO_CITY_FEEDER_TOPO_TICKET)
                        .tag("1")
                        .body(lineIds)
                        .build();
                rocketMQTemplate.sendAsyncMessage(messageEntity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
