package com.xydl.cac.service.impl;

import com.xydl.cac.entity.*;
import com.xydl.cac.entity.constants.Constants;
import com.xydl.cac.exception.BusinessException;
import com.xydl.cac.iec.IecClient;
import com.xydl.cac.model.IcdAttUpdateModel;
import com.xydl.cac.model.StaticVariable;
import com.xydl.cac.repository.*;
import com.xydl.cac.service.DataService;
import com.xydl.cac.service.IcdFileConfigService;
import com.xydl.cac.util.IcdXmlUtil;
import com.xydl.cac.util.Md5;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class IcdFileConfigServiceImpl implements IcdFileConfigService {

    @Resource
    IcdFileRepository fileRepository;
    @Resource
    IcdIedRepository iedRepository;
    @Resource
    IcdConfigTypeRepository configRepository;
    @Resource
    IcdConfigTypeAttRepository attRepository;
    @Resource
    IcdConfigTypeInstRepository instRepository;
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    RptparamindexRepository rptparamindexRepository;
    @Resource
    DataService dataService;
    @Resource
    IedDlConfigRepository iedDlConfigRepository;

    @Override
    public void upload(String xml, String filename, int srv) throws Exception {
        String md5 = Md5.getMD5Code(xml);
        List<IcdFile> files = fileRepository.findByMd5AndSrv(md5, srv);
        if (!CollectionUtils.isEmpty(files)) {
            throw new BusinessException("该文件已存在");
        }

        IcdFile icdFile = IcdXmlUtil.loadIcdType(xml);
        icdFile.setMd5(md5);
        icdFile.setFilename(filename);
        icdFile.setSrv(srv);
        icdFile.setStart(Constants.FALSE);
        fileRepository.save(icdFile);
        if (srv == Constants.Server) {
            return;
        }
        for (IcdIed ied : icdFile.getIedList()) {
            ied.setIcdFileId(icdFile.getId());
            ied.setStart(Constants.FALSE);
            iedRepository.save(ied);
        }
        for (IcdConfigType config : icdFile.getConfigList()) {
            IcdIed ied = this.findIcdIed(icdFile.getIedList(), config.getIedName());
            if (ied != null) {
                config.setIcdIedId(ied.getId());
            }
            configRepository.save(config);

            attRepository.deleteByIcdConfigTypeId(config.getId());
            if (config.getAttMap() != null) {
                Collection<IcdConfigTypeAtt> attList = config.getAttMap().values();
                for (IcdConfigTypeAtt item : attList) {
                    item.setIcdConfigTypeId(config.getId());
                    item.buildInsts();
                }
                attRepository.saveAll(attList);
            }

            instRepository.deleteByIcdConfigTypeId(config.getId());
            if (config.getInstMap() != null) {
                Collection<IcdConfigTypeInst> instList = config.getInstMap().values();
                for (IcdConfigTypeInst item : instList) {
                    item.setIcdConfigTypeId(config.getId());
                }
                instRepository.saveAll(instList);
            }
        }
    }

    @Override
    public List<IcdFile> listFile(int srv) {
        List<IcdFile> files = fileRepository.findBySrv(srv);
        return files;
    }

    @Override
    public List<IcdIed> listIed() {
        List<IcdIed> result = new ArrayList<>();
        List<IcdFile> icdFileList = fileRepository.findBySrv(Constants.Client);
        if (CollectionUtils.isEmpty(icdFileList)) {
            return result;
        }
        for (IcdFile icdFile : icdFileList) {
            List<IcdIed> iedList = iedRepository.findByIcdFileId(icdFile.getId());
            for (IcdIed ied : iedList) {
                if (StringUtils.isNotBlank(ied.getIp())) {
                    ied.setConnected(false);
                    ied.setRetry(0);
                    ied.setSeconds(0);
                    IecClient iecClient = StaticVariable.realTimeClientMap.get(ied.getId());
                    if (iecClient != null) {
                        ied.setRetry(iecClient.retry);
                        ied.setConnected(iecClient.connected);
                        ied.setSeconds(iecClient.seconds);
                    }
                    result.add(ied);
                }
            }
        }
        return result;
    }

    private IcdIed findIcdIed(List<IcdIed> list, String name) {
        for (IcdIed ied : list) {
            if (ied.getName().equalsIgnoreCase(name)) {
                return ied;
            }
        }
        return null;
    }

    @Override
    public List<String> iedList() {
        String sql = "SELECT DISTINCT ied_name FROM icd_config_type";
        List<String> list = jdbcTemplate.queryForList(sql, String.class);
        return list;
    }

    @Override
    public List<IcdConfigType> list(String iedName) throws Exception {
        List<IcdConfigType> result;
        if (StringUtils.isNotBlank(iedName)) {
            result = configRepository.findByIedName(iedName);
        } else {
            result = configRepository.findAll();
        }
        for (IcdConfigType item : result) {
            List<IcdConfigTypeAtt> atts = attRepository.findByIcdConfigTypeId(item.getId());
            item.setAttList(atts);
            List<IcdConfigTypeInst> insts = instRepository.findByIcdConfigTypeId(item.getId());
            item.setInstList(insts);
            for (IcdConfigTypeInst inst : insts) {
                String param = item.getIedName() + item.getLdeviceInst() + "/" + item.getLnClass()
                        + inst.getInst();
                inst.setParamIndex(param);
            }
        }
        return result;
    }

    @Override
    public void update(IcdConfigType item) throws Exception {
        Optional<IcdConfigType> optional = configRepository.findById(item.getId());
        if (!optional.isPresent()) {
            throw new BusinessException("未找到该项");
        }
        IcdConfigType r = optional.get();
        if (r.getTableName() != null && !r.getTableName().equals(item.getTableName())) {
            List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(r.getId());
            for (IcdConfigTypeAtt att : attList) {
                att.setColName(null);
            }
            attRepository.saveAll(attList);
        }
        r.setTableName(item.getTableName());
        configRepository.save(r);
    }

    @Override
    public void updateAtt(IcdAttUpdateModel model) throws Exception {
        if (CollectionUtils.isEmpty(model.getIdList())) {
            throw new BusinessException("id列表不能为空");
        }
        for (Integer id : model.getIdList()) {
            Optional<IcdConfigTypeAtt> optional = attRepository.findById(id);
            if (!optional.isPresent()) {
                throw new BusinessException("未找到该项" + id);
            }
            IcdConfigTypeAtt r = optional.get();
            r.setColName(model.getColName());
            attRepository.save(r);
        }
    }

    @Override
    public void delete(Integer id) {
        instRepository.deleteByIcdConfigTypeId(id);
        attRepository.deleteByIcdConfigTypeId(id);
        configRepository.deleteById(id);
    }

    @Override
    public void deleteSrv(Integer fileId) throws BusinessException {
        Optional<IcdFile> optional = fileRepository.findById(fileId);
        if (!optional.isPresent()) {
            throw new BusinessException("未找到该文件");
        }
        IcdFile icdFile = optional.get();
        if (icdFile.getStart().intValue() == Constants.TRUE) {
            throw new BusinessException("请先去控制台停止该服务端");
        }
        fileRepository.deleteById(fileId);
    }

    @Override
    public void deleteAtt(Integer attid) {
        attRepository.deleteById(attid);
    }

    @Override
    public void clearAll() {
        dataService.clearAllBind();
        instRepository.deleteAll();
        attRepository.deleteAll();
        configRepository.deleteAll();
        fileRepository.deleteAll();
        iedRepository.deleteAll();
        iedDlConfigRepository.deleteAll();
    }

    @Override
    public List<String> compare61850() {
        List<String> param618List = new ArrayList<>();
        List<Rptparamindex> rptList = rptparamindexRepository.findAll();
        for (Rptparamindex rpt : rptList) {
            param618List.add(rpt.getParamindex());
        }

        List<String> paramList = new ArrayList<>();
        List<IcdConfigType> typeLIst = configRepository.findAll();
        for (IcdConfigType type : typeLIst) {
            List<IcdConfigTypeInst> instList = instRepository.findByIcdConfigTypeId(type.getId());
            List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
            for (IcdConfigTypeInst inst : instList) {
                String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                        + inst.getInst();
                for (IcdConfigTypeAtt att : attList) {
                    if (att.containInst(inst.getInst())) {
                        String paramindex = param + "$" + att.getParam();
                        paramList.add(paramindex);
                    }
                }
            }
        }

        List<String> result = new ArrayList<>();
        for (String str : param618List) {
            if (!paramList.contains(str)) {
                result.add("少了" + str);
            }
        }
        for (String str : paramList) {
            if (!param618List.contains(str)) {
                result.add("多了" + str);
            }
        }
        return result;
    }

    @Override
    public void generateParamindex() throws Exception {
        List<IcdConfigType> typeLIst = configRepository.findAll();
        for (IcdConfigType type : typeLIst) {
            List<IcdConfigTypeInst> instList = instRepository.findByIcdConfigTypeId(type.getId());
            List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
            for (IcdConfigTypeInst inst : instList) {
                String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                        + inst.getInst();
                for (IcdConfigTypeAtt att : attList) {
                    if (att.containInst(inst.getInst())) {
                        String paramindex = param + "$" + att.getParam();
                        List<Rptparamindex> rptList = rptparamindexRepository.findAllByParamindexEquals(paramindex);
                        if (CollectionUtils.isEmpty(rptList)) {
                            Rptparamindex rpt = Rptparamindex.builder()
                                    .paramindex(paramindex)
                                    .objid(0)
                                    .build();
                            rptparamindexRepository.save(rpt);
                        }
                    }
                }
            }
        }
    }

    @Override
    public List<IcdConfigTypeInst> listParamindex(String iedName) {
        List<IcdConfigTypeInst> result = new ArrayList<>();
        List<IcdConfigType> typeList = configRepository.findByIedName(iedName);
        for (IcdConfigType type : typeList) {
            List<IcdConfigTypeInst> instList = instRepository.findByIcdConfigTypeId(type.getId());
            List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
            for (IcdConfigTypeInst inst : instList) {
                String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                        + inst.getInst();
                inst.setParamIndex(param);
                for (IcdConfigTypeAtt att : attList) {
                    if (att.containInst(inst.getInst())) {
                        String paramindex = param + "." + att.getDoName();
                        inst.addAtt(paramindex);
                    }
                }
            }
            result.addAll(instList);
        }
        return result;
    }

}
