package com.njcn.influx.service.impl;

import com.jcraft.jsch.ChannelSftp;

import com.njcn.influx.bo.po.OracleRmpEventDetailPO;
import com.njcn.influx.bo.po.PqDevice;
import com.njcn.influx.bo.po.PqsEventLog;
import com.njcn.influx.component.WaveFileComponent;
import com.njcn.influx.component.dto.WaveDataDTO;
import com.njcn.influx.config.OtherConfig;
import com.njcn.influx.config.TargetConfig;
import com.njcn.influx.event.cause.jna.QvvrCauseDLL;
import com.njcn.influx.event.cause.model.DataFeature;
import com.njcn.influx.event.cause.model.EventAnalysisDTO;
import com.njcn.influx.event.type.jna.QvvrDLL;
import com.njcn.influx.mapper.OracleRmpEventDetailPOMapper;
import com.njcn.influx.mapper.PqDeviceMapper;
import com.njcn.influx.service.PqsEventLogService;
import com.njcn.influx.service.RmpEventDetailService;
import com.njcn.influx.sftp.SftpClient;
import com.sun.jna.Memory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.util.Date;
import java.util.List;
import java.util.Objects;


@Service
@Slf4j
@RequiredArgsConstructor
public class EventAsyncService {




    private  final  RmpEventDetailService rmpEventDetailService;

    private final PqDeviceMapper pqDeviceMapper;
    private final WaveFileComponent waveFileComponent;

    private final OtherConfig config;

    private final TargetConfig targetConfig;

    private final OracleRmpEventDetailPOMapper oracleRmpEventDetailPOMapper;
    private final PqsEventLogService pqsEventLogService;

    @Value("${business.dealFlag:true}")
    private Boolean dealFlag;
    @Value("${business.upLoadFlag:true}")
    private Boolean upLoadFlag;


    // ============================
    // 文件同步 + 高级算法
    // ============================
//    @Async("eventTaskExecutor")
    public void asyncHandleEvent(OracleRmpEventDetailPO detail ) {
        try {
            log.info("异步处理事件：{} 文件：{}", detail.getEventId(), detail.getWavePath());
            // ========== 1. 查看波形文件是否存在 ==========
            PqDevice pqDevice = pqDeviceMapper.selectByLineId(detail.getMeasurementPointId());
            String wavePath = config.getWavePath();
            String cfgPath = wavePath + File.separator + pqDevice.getIp() + File.separator + detail.getWavePath() + ".CFG" ;
            String datPath = wavePath + File.separator + pqDevice.getIp() + File.separator + detail.getWavePath() + ".DAT" ;


            log.info("本地磁盘波形文件路径----" + cfgPath);
            InputStream cfgStream = getFileInputStreamByFilePath(cfgPath);
            InputStream datStream = getFileInputStreamByFilePath(datPath);

            if((Objects.nonNull(cfgStream)&&Objects.nonNull(datStream))){
                // ========== 2. 高级算法更新原因/类型 ==========
                if(dealFlag){
                    EventAnalysisDTO eventAnalysisDTO = null;
                    try {
                        eventAnalysisDTO = advancedAlgorithm(cfgStream, datStream);
                        log.info("暂降原因："+eventAnalysisDTO.getCause()+"----暂降类型："+eventAnalysisDTO.getType());
                        oracleRmpEventDetailPOMapper.updateCause(eventAnalysisDTO.getCause(),detail.getEventId());
                        oracleRmpEventDetailPOMapper.updateType(eventAnalysisDTO.getType(),detail.getEventId());
                        pqsEventLogService.lambdaUpdate().set(PqsEventLog::getDealflag,1).set(PqsEventLog::getUpdatetime,new Date()).eq(PqsEventLog::getEventdetailIndex,detail.getEventId()).update();
                    } catch (Exception e) {
                        pqsEventLogService.lambdaUpdate().set(PqsEventLog::getRemark,e.getMessage().length()>50?e.getMessage().substring(50):e.getMessage()).set(PqsEventLog::getUpdatetime,new Date()).eq(PqsEventLog::getEventdetailIndex,detail.getEventId()).update();

                    }

                }
                if(upLoadFlag){
                    // ========== 4. SFTP文件同步 ==========
                    try {
                        syncFileToSftp(pqDevice.getIp(), detail.getWavePath(), cfgPath, datPath);
                        pqsEventLogService.lambdaUpdate().set(PqsEventLog::getFileupflag,1).set(PqsEventLog::getUpdatetime,new Date()).eq(PqsEventLog::getEventdetailIndex,detail.getEventId()).update();

                    } catch (Exception e) {
                        pqsEventLogService.lambdaUpdate().set(PqsEventLog::getRemark,e.getMessage().length()>50?e.getMessage().substring(50):e.getMessage()).set(PqsEventLog::getUpdatetime,new Date()).eq(PqsEventLog::getEventdetailIndex,detail.getEventId()).update();

                    }

                }

                rmpEventDetailService.syncToMysql(detail.getEventId());

            }

        } catch (Exception e) {
            log.error("异步处理失败 eventId:{}", detail.getEventId(), e);
        }

    }

    // ==================
    // 已修复：SFTP上传（无reset，无mark异常）
    // ==================
    private void syncFileToSftp(String deviceIp, String wavePath, String cfgFilePath, String datFilePath) throws Exception {
        try (SftpClient client = new SftpClient() ) {
            client.connect(targetConfig);
            ChannelSftp channel = client.getChannel();

            String remoteDir = targetConfig.getBasePath() + "/" + deviceIp;
            client.createRemoteDirectory(remoteDir);

            String remoteCfg = remoteDir + "/" + wavePath + ".CFG";
            String remoteDat = remoteDir + "/" + wavePath + ".DAT";

            channel.put(new FileInputStream(cfgFilePath), remoteCfg);
            channel.put(new FileInputStream(datFilePath), remoteDat);
            log.info("SFTP上传成功：{}", remoteCfg);

        } catch (Exception e) {
            log.error("SFTP上传失败", e);
            throw new Exception("SFTP上传失败:"+(e.getMessage().length()>50?e.getMessage().substring(50):e.getMessage()));
        }
    }


    // ==================
    // 高级算法：更新 EVENTREASON / EVENTTYPE
    // ==================
    private EventAnalysisDTO advancedAlgorithm(InputStream cfgStream , InputStream datStream) throws Exception {
        EventAnalysisDTO eventAnalysis = new EventAnalysisDTO();
        log.info("执行高级算法：{}");
        WaveDataDTO waveDataDTO = waveFileComponent.getComtradeNoAddPoints(cfgStream, datStream, 0);

        List<List<Float>> listWaveData = waveDataDTO.getListWaveData();
        // 暂降类型
        // 创建数据结构
        QvvrDLL.QvvrDataStruct typeDataStruct = new QvvrDLL.QvvrDataStruct();
        System.out.println("初始化qvvrdll成功-----------");
        typeDataStruct.smp_rate = waveDataDTO.getComtradeCfgDTO().getFinalSampleRate();
        System.out.println("采样率-----------" + typeDataStruct.smp_rate);
        typeDataStruct.smp_len = listWaveData.size();
        System.out.println("波形长度-----------" + listWaveData.size());

        // 获取ABC三相的瞬时数据
        for (int i = 0; i < listWaveData.size(); i++) {
            typeDataStruct.smp_va[i] = listWaveData.get(i).get(1);
            typeDataStruct.smp_vb[i] = listWaveData.get(i).get(2);
            typeDataStruct.smp_vc[i] = listWaveData.get(i).get(3);
        }


        // 执行算法分析 - 直接调用C DLL
        try {
            QvvrDLL.INSTANCE.qvvr_fun(typeDataStruct);

            log.info("调用qvvrdll成功-----------");

            if (typeDataStruct.evt_num > 0) {
                // 全局比较找出最小三相电压特征值
                float globalMinVoltage = Float.MAX_VALUE;
                int globalFaultType = 10;
                for (int i = 0; i < typeDataStruct.evt_num; i++) {
                    QvvrDLL.EventBuffer evt = typeDataStruct.evt_buf[i];
                    for (int j = 0; j < evt.u_min_num; j++) {
                        float u3min = evt.u3_min[j];
                        if (u3min < globalMinVoltage) {
                            globalMinVoltage = u3min;
                            globalFaultType = evt.qvvr_cata_type[j];
                        }
                    }
                }
                eventAnalysis.setType(globalFaultType);
            } else {
                eventAnalysis.setType(DataFeature.TYPE10);
            }
            System.out.println("结束qvvrdll方法调用-----------");
        } catch (Exception e) {
            eventAnalysis.setType(DataFeature.TYPE10);
            eventAnalysis.setTypeFlag(0);
        }


        // 暂降原因JNA的方式
        QvvrCauseDLL.QvvrDataStruct causeDataStruct = new QvvrCauseDLL.QvvrDataStruct();
        causeDataStruct.smp_rate = waveDataDTO.getComtradeCfgDTO().getFinalSampleRate();
        causeDataStruct.smp_len = listWaveData.size();
        // 获取ABC三相的瞬时数据
        for (int i = 0; i < listWaveData.size(); i++) {
            causeDataStruct.smp_va[i] = listWaveData.get(i).get(1);
            causeDataStruct.smp_vb[i] = listWaveData.get(i).get(2);
            causeDataStruct.smp_vc[i] = listWaveData.get(i).get(3);
        }
        // 执行算法分析 - 直接调用C DLL
        try {
            QvvrCauseDLL.INSTANCE.qvvr_fun_cause(causeDataStruct);
            eventAnalysis.setCause(causeDataStruct.cause);
            if (causeDataStruct.no_cal != 0) {
                eventAnalysis.setCauseFlag(0);
            }
        } catch (Exception e) {
            eventAnalysis.setCause(DataFeature.CAUSE_TYPE0);
            eventAnalysis.setCauseFlag(0);
        }
        System.out.println("暂降原因分析完毕===============");
        System.out.println("cause:" + eventAnalysis);
        return eventAnalysis;
    }

    public InputStream getFileInputStreamByFilePath(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            InputStream inputStream;
            try {
                inputStream = Files.newInputStream(file.toPath());
                if (inputStream.available() < 1) {
                    return null;
                }
                return inputStream;
            } catch (IOException e) {
                return null;
            }
        } else {
            return null;
        }
    }
}