package com.xydl.cac.iec;

import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.FileInformation;
import com.xydl.cac.config.BizConfig;
import com.xydl.cac.entity.*;
import com.xydl.cac.entity.constants.Constants;
import com.xydl.cac.model.StaticVariable;
import com.xydl.cac.repository.*;
import com.xydl.cac.service.DataService;
import com.xydl.cac.service.IedDlRecordService;
import com.xydl.cac.socket.WebSocketServer;
import com.xydl.cac.spectrogram.SpectrogramHandler;
import com.xydl.cac.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Slf4j
public class IEDCollectService {
    IcdConfigTypeRepository _configRepository;
    IcdConfigTypeAttRepository _attRepository;
    IcdConfigTypeInstRepository _instRepository;
    RptparamindexRepository _rptparamindexRepository;
    IedDlRecordService _dlRecordService;
    DataService _dataService;
    IecClient iecClient;
    IcdIed ied;
    String xml;
    WebSocketServer _webSocketServer;
    BizConfig _bizConfig;
    WarningRepository _warningRepository;
    SpectrogramHandler _spectrogramHandler;
    boolean _warning;

    String folder = "/record";
    HashMap<Integer, String> eqmidTimeMap = new HashMap<>();

    public IEDCollectService(IcdConfigTypeRepository configRepository, IcdConfigTypeAttRepository attRepository,
                             IcdConfigTypeInstRepository instRepository, RptparamindexRepository rptparamindexRepository,
                             IedDlRecordService dlRecordService, DataService dataService,
                             String xml, IcdIed ied,
                             WebSocketServer webSocketServer, BizConfig bizConfig, boolean warning,
                             WarningRepository warningRepository, SpectrogramHandler spectrogramHandler) {
        _configRepository = configRepository;
        _attRepository = attRepository;
        _instRepository = instRepository;
        _rptparamindexRepository = rptparamindexRepository;
        _dlRecordService = dlRecordService;
        _dataService = dataService;
        this.xml = xml;
        this.ied = ied;
        _webSocketServer = webSocketServer;
        _bizConfig = bizConfig;
        _warning = warning;
        _warningRepository = warningRepository;
        _spectrogramHandler = spectrogramHandler;
        iecClient = new IecClient();
    }

    public void connect() throws Exception {
        iecClient.init(ied, xml);
        iecClient.connect();
    }

    public void disconnect() {
        iecClient.disconnect();
    }

    public void collectAndSave(List<Rptparamindex> rptList, List<IedDlConfig> dlList) {
        List<IcdConfigType> configTypeList = _configRepository.findByIcdIedId(ied.getId());
        if (CollectionUtils.isEmpty(configTypeList)) {
            return;
        }
        // 开始连iec61850采集数据
        try {
            log.info("61850开始采集数据, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort());
            this.connect();
            eqmidTimeMap.clear();
            if (!CollectionUtils.isEmpty(rptList)) {
                this.doCollectAndSave(configTypeList, rptList);
            }

            if (!CollectionUtils.isEmpty(dlList)) {
                this.doDownload(dlList);
            }
        } catch (Exception ex) {
            String err = "61850采集数据异常, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()
                    + ", " + ex.getMessage();
            log.error(err, ex);
            if (_warning) {
                this.saveWarning(err);
                String key = ied.getName() + ied.getIp() + ied.getPort();
                if (!StaticVariable.doneWarnMap.containsKey(key)) {
                    StaticVariable.doneWarnMap.put(key, "1");
                    _webSocketServer.sendMessage(err, null);
                }
            }
        } finally {
            iecClient.disconnect();
        }
    }

    private void saveWarning(String err) {
        if (err.length() > 254) {
            err = err.substring(0, 254);
        }
        Warning warning = Warning.builder()
                .zsbName("61850采集数据")
                .dTime(new Date())
                .warnLevel(2)
                .state("1")
                .warnDesc(err)
                .warnTime(new Date())
                .processTime(new Date())
                .build();
        _warningRepository.save(warning);
    }

    private void doCollectAndSave(List<IcdConfigType> configTypeList, List<Rptparamindex> rptList) throws Exception {
        for (IcdConfigType configType : configTypeList) {
            List<IcdConfigTypeInst> instList = _instRepository.findByIcdConfigTypeId(configType.getId());
            List<IcdConfigTypeAtt> attList = _attRepository.findByIcdConfigTypeId(configType.getId());
            for (IcdConfigTypeInst inst : instList) {
                String param = configType.getIedName() + configType.getLdeviceInst() + "/" + configType.getLnClass() + inst.getInst();
                for (IcdConfigTypeAtt att : attList) {
                    if (att.containInst(inst.getInst())) {
                        String paramindexOld = param + "$" + att.getParam();
                        String paramindexNew = param + "." + att.getDoName() + "." + att.getLastName().replace("$", ".");
                        String paramindexT = param + "." + att.getDoName() + ".t";

                        Rptparamindex rpt = this.findRpt(rptList, paramindexOld);
                        if (rpt != null) {
                            this.collectAndSaveValue(paramindexNew, paramindexT, att.getFc(), rpt);
                        }
                    }
                }
            }
        }
    }

    private void collectAndSaveValue(String paramindexNew, String paramindexT, String fc, Rptparamindex rpt) throws Exception {
        // 更新关联关系缓存
        String key = paramindexNew + "_" + fc;
        String value = rpt.getEqmid() + "," + rpt.getColname();
        StaticVariable.paramRelationMap.put(key, value);
        key = paramindexT + "_" + fc;
        value = rpt.getEqmid() + ",acquisitionTime";
        StaticVariable.paramRelationMap.put(key, value);

        // 采集数据
        BasicDataAttribute valueNode = iecClient.getNode(paramindexNew, fc);
        BasicDataAttribute timeNode = iecClient.getNode(paramindexT, fc);
        value = valueNode.getValueString();
        String time = timeNode.getValueString();
        log.info("采集到" + fc + " " + paramindexNew + "=" + value + ", t=" + time);
        if ("NaN".equalsIgnoreCase(value)) {
            return;
        }
        time = DateUtil.fromZoneUTCToLocal(time);
        if (time == null) {
            return;
        }
        time = this.makeSameTime(rpt.getEqmid(), time);
        _dataService.insertData(rpt.getTablename(), rpt.getEqmid(), time, rpt.getColname(), value);

        // 更新最新数据缓存
        StaticVariable.updateLastData(rpt.getEqmid(), rpt.getColname(), value, time);

        // 更新服务端
        StaticVariable.updateServerNodeValue(valueNode);
        StaticVariable.updateServerNodeValue(timeNode);
    }

    private String makeSameTime(Integer eqmid, String time) {
        String sameTime = eqmidTimeMap.get(eqmid);
        if (StringUtils.isBlank(sameTime)) {
            sameTime = time;
            eqmidTimeMap.put(eqmid, sameTime);
        }
        return sameTime;
    }

    private Rptparamindex findRpt(List<Rptparamindex> rptList, String paramindex) {
        for (Rptparamindex rpt : rptList) {
            if (rpt.getParamindex().equals(paramindex)) {
                return rpt;
            }
        }
        return null;
    }

    private void doDownload(List<IedDlConfig> dlList) {
        for (IedDlConfig config : dlList) {
            this.downloadOne(config);
        }
    }

    private void downloadOne(IedDlConfig config) {
        if (config.getActive() == null || config.getActive().intValue() == Constants.FALSE) {
            return;
        }
        if (StringUtils.isBlank(config.getPath())) {
            return;
        }
        if (!config.getPath().endsWith("/")) {
            config.setPath(config.getPath() + "/");
        }
        if (config.getDevId() == null) {
            return;
        }
        try {
            String localPath = folder + "/" + config.getDevId();
            List<FileInformation> fileList = iecClient.listFile(config.getPath());
            for (FileInformation file : fileList) {
                String filename = file.getFilename();
                if (!filename.endsWith("/")) {
                    if (matchSuffix(filename, config.getSuffix())
                            && matchContain(filename, config.getContain())) {
                        IedDlRecord record = new IedDlRecord();
                        record.setConfigId(config.getId());
                        record.setDevId(config.getDevId());
                        record.setTypeId(config.getSensor().getTypeId());
                        record.setFilename(filename);
                        record.setRemotePath(config.getPath() + filename);
                        boolean exist = _dlRecordService.exist(record);
                        if (!exist) {
                            String relativePath = localPath + "/" + filename;
                            String localFullPath = _bizConfig.getDatapath() + relativePath;
                            iecClient.getFile(record.getRemotePath(), localFullPath, config.getTodel());
                            record.setPath(_bizConfig.getDataNginxPath() + relativePath);
                            log.info("采集到" + record.getRemotePath());
                            _spectrogramHandler.processFile(record);
                            _dlRecordService.add(record);
                        }
                    }
                }
            }
        } catch (Exception ex) {
            String err = "61850采集文件异常, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", path=" + config.getPath();
            log.error(err, ex);
            String key = ied.getName() + ied.getIp() + ied.getPort() + config.getPath();
            if (!StaticVariable.doneWarnMap.containsKey(key)) {
                StaticVariable.doneWarnMap.put(key, "1");
                _webSocketServer.sendMessage(err, null);
            }
        }
    }

    private boolean matchSuffix(String filename, String suffix) {
        if (StringUtils.isBlank(suffix)) {
            return true;
        } else {
            if (filename.toLowerCase().endsWith(suffix.toLowerCase())) {
                return true;
            }
            return false;
        }
    }

    private boolean matchContain(String filename, String contain) {
        if (StringUtils.isBlank(contain)) {
            return true;
        } else {
            if (filename.toLowerCase().contains(contain.toLowerCase())) {
                return true;
            }
            return false;
        }
    }

}
