package com.xydl.cac.service.impl;

import com.xydl.cac.entity.*;
import com.xydl.cac.exception.BusinessException;
import com.xydl.cac.model.BindDetail;
import com.xydl.cac.model.BindingModel;
import com.xydl.cac.model.ColumnModel;
import com.xydl.cac.model.Response;
import com.xydl.cac.repository.*;
import com.xydl.cac.service.DataService;
import com.xydl.cac.service.ModevTypeService;
import com.xydl.cac.service.ParamBindService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class ParamBindServiceImpl implements ParamBindService {

    @Resource
    BdzRepository bdzRepository;
    @Resource
    JgRepository jgRepository;
    @Resource
    ZsbRepository zsbRepository;
    @Resource
    NSensorRepository sensorRepository;
    @Resource
    ModevTypeService modevTypeService;
    @Resource
    IcdConfigTypeRepository typeRepository;
    @Resource
    IcdConfigTypeInstRepository instRepository;
    @Resource
    IcdConfigTypeAttRepository attRepository;
    @Resource
    RptparamindexRepository rptparamindexRepository;
    @Resource
    DataService dataService;

    @Override
    public List<Bdz> getTrunk() throws Exception {
        List<Bdz> bdzList = bdzRepository.findAll();
        for (Bdz bdz : bdzList) {
            List<Jg> jgList = jgRepository.findByBdzid(bdz.getId());
            bdz.setChildren(jgList);
            for (Jg jg : jgList) {
                jg.setBdzName(bdz.getMc());
                List<Zsb> zsbList = zsbRepository.findByJgid(jg.getId());
                jg.setChildren(zsbList);
            }
        }
        return bdzList;
    }

    @Override
    public List<Bdz> getTree(boolean ignoreEmpty) throws Exception {
        // 获取全量
        List<Bdz> bdzList = bdzRepository.findAll();
        HashMap<Integer, Bdz> bdzMap = new HashMap<>();
        for (Bdz bdz : bdzList) {
            bdzMap.put(bdz.getId(), bdz);
        }
        List<Jg> jgList = jgRepository.findAll();
        HashMap<Integer, Jg> jgMap = new HashMap<>();
        for (Jg jg : jgList) {
            jgMap.put(jg.getId(), jg);
        }
        List<Zsb> zsbList = zsbRepository.findAll();
        HashMap<Integer, Zsb> zsbMap = new HashMap<>();
        for (Zsb zsb : zsbList) {
            zsbMap.put(zsb.getId(), zsb);
        }
        Specification<NSensor> specification = (root, query, builder) -> {
            Predicate predicate = builder.conjunction();
            query.orderBy(builder.asc(root.get("orderNum")));
            return predicate;
        };
        List<NSensor> sensorList = sensorRepository.findAll(specification);

        // 每一个放入上一层
        for (NSensor sensor : sensorList) {
            Zsb zsb = zsbMap.get(sensor.getZsbId());
            if (zsb != null) {
                zsb.addChild(sensor);
            }
        }
        for (Zsb zsb : zsbList) {
            Jg jg = jgMap.get(zsb.getJgid());
            if (jg != null) {
                jg.addChild(zsb, ignoreEmpty);
            }
        }
        for (Jg jg : jgList) {
            Bdz bdz = bdzMap.get(jg.getBdzid());
            if (bdz != null) {
                bdz.addChild(jg, ignoreEmpty);
            }
        }
        List<Bdz> result = new ArrayList<>();
        if (ignoreEmpty) {
            for (Bdz bdz : bdzList) {
                if (!CollectionUtils.isEmpty(bdz.getChildren())) {
                    result.add(bdz);
                }
            }
        } else {
            result = bdzList;
        }
        return result;
    }

    @Override
    public List<IcdConfigTypeInst> instList(String iedName) {
        List<IcdConfigTypeInst> result = new ArrayList<>();
        List<IcdConfigType> typeList = typeRepository.findByIedName(iedName);
        for (IcdConfigType type : typeList) {
            List<IcdConfigTypeInst> instList = instRepository.findByIcdConfigTypeId(type.getId());
            for (IcdConfigTypeInst inst : instList) {
                String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                        + inst.getInst();
                inst.setParamIndex(param);
            }
            result.addAll(instList);
        }
        return result;
    }

    @Override
    public Response preview(BindingModel item) throws Exception {
        Optional<NSensor> optionalNSensor = sensorRepository.findById(item.getSensorId());
        if (!optionalNSensor.isPresent()) {
            throw new BusinessException("未找到该监测装置, sensorId=" + item.getSensorId());
        }
        NSensor sensor = optionalNSensor.get();
        if (sensor.getTypeId() == null) {
            throw new BusinessException("该装置缺少类型id信息");
        }
        ModevType modevType = modevTypeService.detail(sensor.getTypeId());
        sensor.setTableName(modevType.getTablename());
        sensor.setTypeName(modevType.getMc());
        Optional<IcdConfigTypeInst> optionalInst = instRepository.findById(item.getIcdid());
        if (!optionalInst.isPresent()) {
            throw new BusinessException("未找到该ICD逻辑设备实例, icdid=" + item.getIcdid());
        }
        IcdConfigTypeInst inst = optionalInst.get();
        Optional<IcdConfigType> optionalType = typeRepository.findById(inst.getIcdConfigTypeId());
        if (!optionalType.isPresent()) {
            throw new BusinessException("未找到该实例对应的ICD配置类型, icdid=" + item.getIcdid());
        }
        IcdConfigType type = optionalType.get();

        String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                + inst.getInst();
        List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
        List<String> msgList = new ArrayList<>();
        for (IcdConfigTypeAtt att : attList) {
            if (StringUtils.isBlank(att.getColName()) && att.containInst(inst.getInst()) && att.getFc().equalsIgnoreCase("MX")) {
                msgList.add(att.getDoName() + "该属性还未配置绑定字段");
            } else {
//                String paramindex = param + "$" + att.getParam();
//                Optional<Rptparamindex> optionalRpt = rptparamindexRepository.findById(paramindex);
//                if (!optionalRpt.isPresent()) {
//                    throw new BusinessException("未找到该Rptparamindex，对象参引=" + paramindex);
//                }
            }
        }

        Response resp = Response.success(attList);
        if (StringUtils.isBlank(type.getTableName())) {
            msgList.add("该ICD配置类型还未设置对应的tableName");
        } else if (!type.getTableName().equals(sensor.getTableName())) {
            msgList.add("该ICD配置类型的tableName(" + type.getTableName() + ")和该监测装置类型的tableName(" + sensor.getTableName() + ")不一致");
        }
        if (msgList.size() > 0) {
            String message = msgList.stream().collect(Collectors.joining("\n\r"));
            resp.setWarnMsg(message);
        }
        return resp;
    }

    @Override
    public void bind(BindingModel item) throws Exception {
        Optional<NSensor> optionalNSensor = sensorRepository.findById(item.getSensorId());
        if (!optionalNSensor.isPresent()) {
            throw new BusinessException("未找到该监测装置, sensorId=" + item.getSensorId());
        }
        NSensor sensor = optionalNSensor.get();

        Optional<IcdConfigTypeInst> optionalInst = instRepository.findById(item.getIcdid());
        if (!optionalInst.isPresent()) {
            throw new BusinessException("未找到该ICD逻辑设备实例, icdid=" + item.getIcdid());
        }
        IcdConfigTypeInst inst = optionalInst.get();
        Optional<IcdConfigType> optionalType = typeRepository.findById(inst.getIcdConfigTypeId());
        if (!optionalType.isPresent()) {
            throw new BusinessException("未找到该实例对应的ICD配置类型, icdid=" + item.getIcdid());
        }
        IcdConfigType type = optionalType.get();

        List<NSensor> list = sensorRepository.findByIcdIdAndIdIsNot(item.getIcdid(), item.getSensorId());
        if (!CollectionUtils.isEmpty(list)) {
            throw new BusinessException("该逻辑设备实例已被" + list.get(0).getName() + "绑定");
        }

        List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());

        if (StringUtils.isNotBlank(sensor.getTableName())) {
            List<ColumnModel> columnList = dataService.getDataTableColumns(sensor.getTableName());
            for (IcdConfigTypeAtt att : attList) {
                if (StringUtils.isNotBlank(att.getColName())) {
                    boolean found = false;
                    for (ColumnModel col : columnList) {
                        if (col.getName().equals(att.getColName())) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        throw new BusinessException("当前监控设备对应的表" + sensor.getTableName() + "里不存在配置属性"
                                + att.getDoName() + "绑定的字段" + att.getColName());
                    }
                }
            }
        }

        sensor.setIcdId(item.getIcdid());
        sensorRepository.save(sensor);
    }

    @Override
    public void unbind(Integer sensorId) throws Exception {
        Optional<NSensor> optionalNSensor = sensorRepository.findById(sensorId);
        if (!optionalNSensor.isPresent()) {
            throw new BusinessException("未找到该监测装置, sensorId=" + sensorId);
        }
        NSensor sensor = optionalNSensor.get();
        sensor.setIcdId(null);
        sensorRepository.save(sensor);
    }

    @Override
    public BindDetail getBind(Integer sensorId) throws Exception {
        Optional<NSensor> optionalNSensor = sensorRepository.findById(sensorId);
        if (!optionalNSensor.isPresent()) {
            throw new BusinessException("未找到该监测装置");
        }
        NSensor sensor = optionalNSensor.get();
        ModevType modevType = modevTypeService.detail(sensor.getTypeId());
        sensor.setTableName(modevType.getTablename());

        BindDetail result = new BindDetail();
        result.setSensorId(sensorId);
        if (StringUtils.isNotBlank(sensor.getTableName())) {
            List<ColumnModel> columnList = dataService.getDataTableColumns(sensor.getTableName());
            result.setColumnList(columnList);
        }

        if (sensor.getIcdId() != null) {
            result.setIcdid(sensor.getIcdId());
            Optional<IcdConfigTypeInst> optionalInst = instRepository.findById(sensor.getIcdId());
            if (optionalInst.isPresent()) {
                IcdConfigTypeInst inst = optionalInst.get();
                Optional<IcdConfigType> optionalType = typeRepository.findById(inst.getIcdConfigTypeId());
                if (optionalType.isPresent()) {
                    IcdConfigType type = optionalType.get();
                    result.setIedName(type.getIedName());
                    String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                            + inst.getInst();
                    List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
                    result.setAttList(attList);
                }
            }
        }
        return result;
    }

    @Override
    public String updateParamindex() throws Exception {
        List<NSensor> sensorList = sensorRepository.findByIcdIdIsNotNull();
        if (!CollectionUtils.isEmpty(sensorList)) {
            for (NSensor item : sensorList) {
                generateOne(item);
            }
            return "已对" + sensorList.size() + "条绑定数据生成对应的61850参引数据";
        } else {
            throw new BusinessException("无任何绑定数据");
        }
    }

    private void generateOne(NSensor item) throws Exception {
        Optional<IcdConfigTypeInst> optionalInst = instRepository.findById(item.getIcdId());
        if (!optionalInst.isPresent()) {
            throw new BusinessException("未找到该ICD逻辑设备实例, sensorId=" + item.getId() + ", icdid=" + item.getIcdId());
        }
        IcdConfigTypeInst inst = optionalInst.get();
        Optional<IcdConfigType> optionalType = typeRepository.findById(inst.getIcdConfigTypeId());
        if (!optionalType.isPresent()) {
            throw new BusinessException("未找到该实例对应的ICD配置类型, icdid=" + item.getIcdId());
        }
        IcdConfigType type = optionalType.get();
        String param = type.getIedName() + type.getLdeviceInst() + "/" + type.getLnClass()
                + inst.getInst();
        List<IcdConfigTypeAtt> attList = attRepository.findByIcdConfigTypeId(type.getId());
        for (IcdConfigTypeAtt att : attList) {
            if (StringUtils.isNotBlank(att.getColName()) && att.containInst(inst.getInst())) {
                String paramindex = param + "$" + att.getParam();
                Optional<Rptparamindex> optionalRpt = rptparamindexRepository.findById(paramindex);
                if (!optionalRpt.isPresent()) {
                    throw new BusinessException(item.getName() + "的字段" + att.getColName() + "对应的属性"
                            + att.getDoName() + "，未找到该Rptparamindex，对象参引=" + paramindex);
                }
                Rptparamindex rpt = optionalRpt.get();
                rpt.setTablename(type.getTableName());
                rpt.setColname(att.getColName());
                rpt.setEqmid(item.getDevId());
                rptparamindexRepository.save(rpt);
            }
        }
    }

    @Override
    public void clearAll() {
        dataService.clearAllBind();
    }

}
