package com.njcn.csharmonic.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.access.enums.AccessEnum;
import com.njcn.access.enums.TypeEnum;
import com.njcn.access.pojo.RspDataDto;
import com.njcn.access.pojo.dto.ReqAndResDto;
import com.njcn.access.pojo.dto.file.FileDto;
import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csdevice.pojo.vo.CsEquipmentDeliveryVO;
import com.njcn.csharmonic.enums.CsHarmonicResponseEnum;
import com.njcn.csharmonic.offline.constant.OfflineConstant;
import com.njcn.csharmonic.offline.log.Log;
import com.njcn.csharmonic.offline.log.vo.NewTaglogbuffer;
import com.njcn.csharmonic.offline.log.vo.TagComtradeCfg;
import com.njcn.csharmonic.offline.mincfg.AnalyseComtradeCfg;
import com.njcn.csharmonic.offline.vo.Response;
import com.njcn.csharmonic.pojo.dto.DownloadMakeUpDto;
import com.njcn.csharmonic.pojo.dto.MakeUpDto;
import com.njcn.csharmonic.pojo.param.MakeUpParam;
import com.njcn.csharmonic.pojo.vo.MakeUpVo;
import com.njcn.csharmonic.service.OfflineDataUploadService;
import com.njcn.influx.pojo.po.cs.PqdData;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.njcn.access.enums.TypeEnum.DATA_48;

/**
 * 类的介绍：离线数据上传解析服务实现类
 *
 * @author gfh
 * @version 1.0.0
 * @createTime 2024/7/22 13:56
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OfflineDataUploadServiceImpl implements OfflineDataUploadService {

    private final MqttPublisher publisher;
    private final RedisUtil redisUtil;
    private final ChannelObjectUtil channelObjectUtil;
    private final FileStorageUtil fileStorageUtil;
    private final EquipmentFeignClient equipmentFeignClient;
    private final CsLineFeignClient csLineFeignClient;

    @Override
    public byte[] uploadAnalysis(List<MultipartFile> files,String type) throws Exception{
        byte[] bytes = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);

        List<Response> responses = new ArrayList<>();
        //min解析较为特殊需要同时解析所有文件
        if(!files.isEmpty() && OfflineConstant.MIN.equals(type)){
            Response response = new Response();
            response.setFilename(OfflineConstant.MIN);
            List<PqdData> pqdData = null;
            try {
                pqdData = AnalyseComtradeCfg.processDirectory(files);
            } catch (Exception e) {
                log.error("min文件夹下的数据文件解析失败");
                response.setState(2);
            }
            response.setObj(pqdData);
            responses.add(response);
        }else{
            for(MultipartFile file : files){
                Response response = new Response();
                response.setFilename(file.getOriginalFilename());
                if(OfflineConstant.COMTRADE.equals(type) && Objects.requireNonNull(file.getOriginalFilename()).contains(OfflineConstant.CFG)) {
                    TagComtradeCfg tagComtradeCfg = null;
                    try {
                        tagComtradeCfg = AnalyseComtradeCfg.analyseComtradeCfg(file);
                    } catch (Exception e) {
                        log.error("当前文件：{}，解析失败",file.getOriginalFilename());
                        response.setState(2);
                    }
                    response.setObj(tagComtradeCfg);
                }else if(OfflineConstant.LOG.equals(type) && Objects.requireNonNull(file.getOriginalFilename()).contains(OfflineConstant.BIN)){
                    List<NewTaglogbuffer> newTaglogbuffers = null;
                    try {
                        newTaglogbuffers = Log.convertLog(file);
                    } catch (Exception e) {
                        log.error("当前文件：{}，解析失败",file.getOriginalFilename());
                        response.setState(2);
                    }
                    response.setObj(newTaglogbuffers);
                }
                responses.add(response);
            }
        }
        try {
            oos.writeObject(responses);
            bytes = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(OfflineConstant.DATATOBYTE_FAIL);
        } finally {
            oos.close();
            baos.close();
        }
        return bytes;
    }

    @Override
    public List<MakeUpVo> getMakeUpData(String lineId) {
        List<MakeUpVo> result = new ArrayList<>();
        try {
            //询问装置项目信息
            askProjectInfo(lineId,null, Integer.parseInt(TypeEnum.TYPE_6.getCode()),null,"DevCmd");
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                String key = AppRedisKey.PROJECT_INFO + lineId;
                Object object = redisUtil.getObjectByKey(key);
                if (!Objects.isNull(object)) {
                    // 创建 DateTimeFormatter 对象并指定格式
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    List<RspDataDto.ProjectInfo> projectInfoList = channelObjectUtil.objectToList(redisUtil.getObjectByKey(key),RspDataDto.ProjectInfo.class);
                    for (RspDataDto.ProjectInfo item : projectInfoList) {
                        MakeUpVo vo = new MakeUpVo();
                        vo.setType("dir");
                        BeanUtils.copyProperties(item,vo);
                        long startTime = item.getPrjTimeStart();
                        if (startTime != 0) {
                            LocalDateTime dateTime = Instant.ofEpochMilli((startTime-8*3600)*1000).atZone(ZoneId.systemDefault()).toLocalDateTime();
                            String formattedDate = dateTime.format(formatter);
                            vo.setStartTime(formattedDate);
                        }
                        long endTime = item.getPrjTimeEnd();
                        if (endTime != -1) {
                            LocalDateTime dateTime = Instant.ofEpochMilli((endTime-8*3600)*1000).atZone(ZoneId.systemDefault()).toLocalDateTime();
                            String formattedDate = dateTime.format(formatter);
                            vo.setEndTime(formattedDate);
                        }
                        result.add(vo);
                    }
                    break;
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (CollUtil.isNotEmpty(result)) {
            result = result.stream().sorted(Comparator.comparing(MakeUpVo::getStartTime).reversed()).collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public List<MakeUpVo> askDirOrFile(String nDid, String prjName, String path, String fileType) {
        List<MakeUpVo> result = new ArrayList<>();
        try {
            //判断文件类型
            //文件夹
            if (Objects.equals("dir",fileType)) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                askProjectInfo(null,nDid, Integer.parseInt(TypeEnum.TYPE_8.getCode()),path,"DevFileCmd");
                Thread.sleep(5000);
                String key = AppRedisKey.PROJECT_INFO + nDid;
                Object object = redisUtil.getObjectByKey(key);
                if (!Objects.isNull(object)) {
                    List<FileDto.DirInfo> projectInfoList = channelObjectUtil.objectToList(redisUtil.getObjectByKey(key),FileDto.DirInfo.class);
                    projectInfoList.forEach(item->{
                        MakeUpVo vo = new MakeUpVo();
                        vo.setPrjName(prjName);
                        vo.setPrjDataPath(item.getName());
                        vo.setType(item.getType());
                        vo.setSize(item.getSize());
                        if (item.getTime() != 0) {
                            LocalDateTime dateTime = Instant.ofEpochMilli(item.getTime()*1000).atZone(ZoneId.systemDefault()).toLocalDateTime();
                            String formattedDate = dateTime.format(formatter);
                            vo.setStartTime(formattedDate);
                        }
                        result.add(vo);
                    });
                }
            }
            //文件
            else {
                System.out.println("file");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public boolean startMakeUpData(MakeUpParam param) {
        boolean result = false;
        List<String> fileList = new ArrayList<>();
        //fixme 这边补召暂不支持多工程补召，防止下载文件时间过长，会出问题。
        String s = param.getProList().get(0);
        //稳态补招
        if (param.getDataTypeList().contains(0)) {
            String minPath = s + "/min";
            List<FileDto.DirInfo> projectInfoList = getFileList(param.getLineId(),param.getNDid(),minPath);
            if (CollectionUtil.isNotEmpty(projectInfoList)) {
                projectInfoList.forEach(item->{
                    String linePath = item.getName();
                    if (timeRange(param.getStartTime(),param.getEndTime(),linePath,"min")) {
                        List<FileDto.DirInfo> lineDataList = getFileList(param.getLineId(),param.getNDid(),linePath);
                        if (CollectionUtil.isNotEmpty(lineDataList)) {
                            fileList.addAll(lineDataList.stream().map(FileDto.DirInfo::getName).collect(Collectors.toList()));
                        }
                    }
                });
            }
        }
        //暂态补招
        if (param.getDataTypeList().contains(1)) {
            //事件
            String logPath = s + "/log";
            List<FileDto.DirInfo> logList = getFileList(param.getLineId(),param.getNDid(),logPath);
            if (CollectionUtil.isNotEmpty(logList)) {
                logList.forEach(item->{
                    if (timeRange(param.getStartTime(),param.getEndTime(),item.getName(),"log")) {
                        fileList.add(item.getName());
                    }
                });
            }
            //录波文件
            String comtradePath = s + "/comtrade";
            List<FileDto.DirInfo> comtradeList = getFileList(param.getLineId(),param.getNDid(),comtradePath);
            if (CollectionUtil.isNotEmpty(comtradeList)) {
                comtradeList.forEach(item->{
                    if (timeRange(param.getStartTime(),param.getEndTime(),item.getName(),"comtrade")) {
                        fileList.add(item.getName());
                    }
                });
            }
        }
        if (CollectionUtil.isNotEmpty(fileList)) {
            //添加record.bin文件
            fileList.add(s + "/record.bin");
            redisUtil.delete(AppRedisKey.MAKE_UP_FILES + param.getNDid());
            CsEquipmentDeliveryVO vo = equipmentFeignClient.queryEquipmentByndid(param.getNDid()).getData();
            DownloadMakeUpDto downloadMakeUpDto = new DownloadMakeUpDto();
            downloadMakeUpDto.setFileList(fileList);
            downloadMakeUpDto.setLineId(param.getLineId());
            downloadMakeUpDto.setDevId(vo.getId());
            downloadMakeUpDto.setAllStep(fileList.size());
            String proName = s.replace("/bd0/cmn/",OssPath.DEV_MAKE_UP_PATH + param.getNDid() + "/");
            downloadMakeUpDto.setEngineeringName(proName);
            redisUtil.saveByKey(AppRedisKey.MAKE_UP_FILES + param.getNDid(),downloadMakeUpDto);
            publisher.send("/makeUpData/" + param.getNDid() +"/" + param.getLineId(), "makeUpData", 1, false);
            log.info("下载的文件列表,{}",fileList);
            result = true;
        } else {
            throw new BusinessException("装置内未找到原始文件!");
        }
        return result;
    }

//    @Override
//    public boolean startMakeUpData(MakeUpParam param) {
//        boolean result = true;
//        try {
//            List<String> fileList = new ArrayList<>();
//            Map<String,List<String>> map = new HashMap<>();
//            String s = param.getProList().get(0);
//
//
//
//
//            //组装文件路径
//            for (String s : param.getProList()) {
//                //稳态补招
//                if (param.getDataTypeList().contains(0)) {
//                    String minPath = s + "/min";
//                    List<FileDto.DirInfo> projectInfoList = getFileList(param.getLineId(),param.getNDid(),minPath);
//                    if (CollectionUtil.isNotEmpty(projectInfoList)) {
//                        projectInfoList.forEach(item->{
//                            String linePath = item.getName();
//                            if (timeRange(param.getStartTime(),param.getEndTime(),linePath,"min")) {
//                                List<FileDto.DirInfo> lineDataList = getFileList(param.getLineId(),param.getNDid(),linePath);
//                                if (CollectionUtil.isNotEmpty(lineDataList)) {
//                                    fileList.addAll(lineDataList.stream().map(FileDto.DirInfo::getName).collect(Collectors.toList()));
//                                }
//                            }
//                        });
//                    }
//                }
//                //暂态补招
//                if (param.getDataTypeList().contains(1)) {
//                    //事件
//                    String logPath = s + "/log";
//                    List<FileDto.DirInfo> logList = getFileList(param.getLineId(),param.getNDid(),logPath);
//                    if (CollectionUtil.isNotEmpty(logList)) {
//                        logList.forEach(item->{
//                            if (timeRange(param.getStartTime(),param.getEndTime(),item.getName(),"log")) {
//                                fileList.add(item.getName());
//                            }
//                        });
//                    }
//                    //录波文件
//                    String comtradePath = s + "/comtrade";
//                    List<FileDto.DirInfo> comtradeList = getFileList(param.getLineId(),param.getNDid(),comtradePath);
//                    if (CollectionUtil.isNotEmpty(comtradeList)) {
//                        comtradeList.forEach(item->{
//                            if (timeRange(param.getStartTime(),param.getEndTime(),item.getName(),"comtrade")) {
//                                fileList.add(item.getName());
//                            }
//                        });
//                    }
//                }
//                if (CollectionUtil.isNotEmpty(fileList)) {
//                    redisUtil.deleteKeysByString(AppRedisKey.MAKE_UP_FILES);
//                    //添加record.bin文件
//                    fileList.add(s + "/record.bin");
//                    map.put(s,fileList);
//                }
//                redisUtil.saveByKey(AppRedisKey.MAKE_UP_FILES + param.getNDid(),map);
//                publisher.send("/makeUpData/" + param.getNDid() +"/" + param.getLineId(), "makeUpData", 1, false);
//                log.info("下载的文件列表,{}",fileList);
//            }
//        } catch (Exception e) {
//            result = false;
//        }
//        return result;
//
//        if (CollectionUtil.isNotEmpty(map)) {
//            List<String> keyList = new ArrayList<>();
//            //获取装置信息
//            CsEquipmentDeliveryVO vo = equipmentFeignClient.queryEquipmentByndid(param.getNDid()).getData();
//            map.forEach((k,v)->{
//                String proName = k.replace("/bd0/cmn/",OssPath.DEV_MAKE_UP_PATH + param.getNDid() + "/");
//                String key = AppRedisKey.PROJECT_INFO + param.getNDid();
//                v.forEach(item->{
//                    redisUtil.delete(key);
//                    Object object = redisUtil.getObjectByKey(AppRedisKey.DEVICE_MID + param.getNDid());
//                    if (!Objects.isNull(object)) {
//                        mid = (Integer) object;
//                    }
//                    askFileInfo(param.getNDid(),mid,item);
//                    try {
//                        Thread.sleep(10000);
//                        FileDto.FileInfo info = channelObjectUtil.objectToSingleObject(redisUtil.getObjectByKey(key),FileDto.FileInfo.class);
//                        String path = deviceFtpFeignClient.downloadFile(param.getNDid(),item,info.getFileSize(),info.getFileCheck()).getData();
//                        String lsFile = generalInfo.getBusinessTempPath() + File.separator + item.split(StrUtil.SLASH)[item.split(StrUtil.SLASH).length - 1];
//                        moveFile(path,getFilePath(item,param.getNDid()),lsFile);
//                        //删除临时文件
//                        File file = new File(lsFile);
//                        if (file.exists()) {
//                            file.delete();
//                        }
//                        //删除下载文件
//                        fileStorageUtil.deleteFile(path);
//                        //存储下载
//                        keyList.add(item);
//                        //推送下载进度
//                        String json = "{allStep:" + fileList.size() * 2 + ",nowStep:" + keyList.size() + "}";
//                        publisher.send("/dataOnlineRecruitment/Progress/" + param.getLineId(), new Gson().toJson(json), 1, false);
//                    } catch (Exception e) {
//                        throw new BusinessException(CsHarmonicResponseEnum.MAKE_UP_ERROR);
//                    }
//                });
//                //下载完成，调用解析接口
//                portableOffLogFeignClient.dataOnlineRecruitment(vo.getId(),param.getLineId(),proName);
//            });
//        }
//    }


    /**
     * 时间处理
     */
    public boolean timeRange(String startTime, String endTime, String filePath, String type) {
        boolean result;
        String data;
        data = filePath.split(StrUtil.SLASH)[filePath.split(StrUtil.SLASH).length - 1];
        switch (type) {
            case "log":
                data = data.split("\\.")[0];
                break;
            case "comtrade":
                data = data.split("_")[1];
                break;
            default:
                break;
        }
        result = judgeTimeRange(startTime,endTime,data);
        return result;
    }


    /**
     * 添加时间判断
     */
    public boolean judgeTimeRange(String startTime, String endTime, String data) {
        boolean result = false;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter formatterNoDelimiter = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate startDate = LocalDate.parse(startTime, formatter);
        LocalDate endDate = LocalDate.parse(endTime, formatter);
        LocalDate targetDate = LocalDate.parse(data, formatterNoDelimiter);
        if (!targetDate.isBefore(startDate) && !targetDate.isAfter(endDate)) {
            log.info("{},日期在指定范围内",data);
            result = true;
        } else {
            log.info("{},日期不在指定范围内",data);
        }
        return result;
    }


    /**
     * 迁移文件
     */
    public void moveFile(String oldPath, String newPath, String lsPath) {
        try {
            InputStream inputStream = fileStorageUtil.getFileStream(oldPath);
            FileOutputStream fileOutputStream = new FileOutputStream(lsPath);
            // 创建一个缓冲区
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, bytesRead);
            }
            File src = new File(lsPath);
            src.getParentFile().mkdirs();
            InputStream is = Files.newInputStream(src.toPath());
            fileStorageUtil.uploadStreamSpecifyName(is, OssPath.DEV_MAKE_UP_PATH,newPath);
            inputStream.close();
            fileOutputStream.close();
            is.close();
        } catch (Exception e) {
            throw new BusinessException(CsHarmonicResponseEnum.MAKE_UP_ERROR);
        }
    }

    /**
     * 获取文件数据
     */
    public List<FileDto.DirInfo> getFileList(String lineId, String nDid, String path) {
        String key = AppRedisKey.PROJECT_INFO + nDid;
        redisUtil.delete(key);
        List<FileDto.DirInfo> result = new ArrayList<>();
        askProjectInfo(lineId,nDid, Integer.parseInt(TypeEnum.TYPE_8.getCode()),path,"DevFileCmd");
        try {
            Thread.sleep(5000);
            Object object = redisUtil.getObjectByKey(key);
            if (!Objects.isNull(object)) {
                result = channelObjectUtil.objectToList(redisUtil.getObjectByKey(key),FileDto.DirInfo.class);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 询问装置项目信息报文
     */
    public void askProjectInfo(String lineId, String nDid, Integer type, String path, String topic) {
        if (StringUtils.isNotBlank(lineId)) {
            CsEquipmentDeliveryPO po = equipmentFeignClient.getDevByLineId(lineId).getData();
            nDid = po.getNdid();
        }
//        String version = csTopicFeignClient.find(nDid).getData();
        String version = "V1";
        ReqAndResDto.Req reqAndResParam = createRequestParameters(lineId, type, path);
        publisher.send("/Pfm/"+topic+"/" + version + "/" + nDid, new Gson().toJson(reqAndResParam), 1, false);
    }

    private ReqAndResDto.Req createRequestParameters(String lineId, Integer type, String path) {
        ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req();
        reqAndResParam.setMid(1);
        reqAndResParam.setDid(1);
        reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode());
        reqAndResParam.setExpire(-1);
        switch (type) {
            case 8454:
                handleType8454(reqAndResParam, lineId);
                break;
            case 8497:
                handleType8497(reqAndResParam, path);
                break;
            default:
                break;
        }
        return reqAndResParam;
    }

    private void handleType8454(ReqAndResDto.Req reqAndResParam, String lineId) {
        if (StringUtils.isNotBlank(lineId)) {
            CsLinePO po = csLineFeignClient.getById(lineId).getData();
            reqAndResParam.setType(8454);
            MakeUpDto makeUpDto = new MakeUpDto();
            makeUpDto.setClDid(po.getClDid());
            makeUpDto.setDataType(Integer.parseInt(DATA_48.getCode()));
            makeUpDto.setDataAttr(0);
            makeUpDto.setOperate(1);
            makeUpDto.setStartTime(-1);
            makeUpDto.setEndTime(-1);
            reqAndResParam.setMsg(makeUpDto);
        }
    }

    private void handleType8497(ReqAndResDto.Req reqAndResParam, String path) {
        reqAndResParam.setType(8497);
        String json = String.format("{\"Name\":\"%s\"}", path);
        JSONObject jsonObject = JSONObject.fromObject(json);
        reqAndResParam.setMsg(jsonObject);
    }

    /**
     * 调整文件路径
     */
    private String getFilePath(String path, String nDid) {
        String[] parts = path.split("/");
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (int i = 3; i < parts.length; i++) {
            if (!first) {
                sb.append("/");
            }
            sb.append(parts[i]);
            first = false;
        }
        return nDid + "/" + sb.toString();
    }

}
