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.model.*;
import com.xydl.cac.repository.I2relationRepository;
import com.xydl.cac.repository.ModevRepository;
import com.xydl.cac.repository.NSensorRepository;
import com.xydl.cac.repository.WarnRuleRepository;
import com.xydl.cac.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
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.*;
import java.util.stream.Collectors;


@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class NSensorServiceImpl implements NSensorService {
    @Resource
    NSensorRepository repository;
    @Resource
    NPointService pointService;
    @Resource
    N103SensorService n103SensorService;
    @Resource
    DataService dataService;
    @Resource
    ZsbService zsbService;
    @Resource
    ModevTypeService modevTypeService;
    @Resource
    ModevTypePointService modevTypePointService;
    @Resource
    ModevRepository modevRepository;
    @Resource
    WarnRuleRepository ruleRepository;
    @Resource
    I2relationRepository i2relationRepository;

    @Override
    public List<NSensor> listAll(Integer zsbid, Integer typeId) throws Exception {
        Specification<NSensor> specification = (root, query, builder) -> {
            Predicate predicate = builder.conjunction();
            if (zsbid != null) {
                predicate.getExpressions().add(builder.equal(root.get("zsbId"), zsbid));
            }
            if (typeId != null) {
                predicate.getExpressions().add(builder.equal(root.get("typeId"), typeId));
            }
            query.orderBy(builder.asc(root.get("orderNum")));
            return predicate;
        };
        List<NSensor> list = repository.findAll(specification);
        this.fillOtherNames(list);
        return list;
    }

    private void fillOtherNames(List<NSensor> list) throws Exception {
        List<Zsb> zsbList = zsbService.listAll(null);
        List<ModevType> modevTypeList = modevTypeService.listAll();
        if (!CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(zsbList)) {
            for (NSensor sensor : list) {
                for (Zsb zsb : zsbList) {
                    if (zsb.getId().equals(sensor.getZsbId())) {
                        sensor.setZsbName(zsb.getMc());
                        sensor.setJgName(zsb.getJgName());
                        break;
                    }
                }
                for (ModevType type : modevTypeList) {
                    if (type.getId().equals(sensor.getTypeId())) {
                        sensor.setTypeName(type.getMc());
                        sensor.setTableName(type.getTablename());
                        List<ModevTypePoint> points = modevTypePointService.listAllCache(sensor.getTypeId());
                        sensor.setTypePoints(points);
                    }
                }
                HashMap<String, String> map = StaticVariable.sensorLastDataMap.get(sensor.getDevId());
                sensor.setLastData(map);
            }
        }
    }

    private void fillOtherName(NSensor sensor) throws Exception {
        ModevType modevType = modevTypeService.detail(sensor.getTypeId());
        sensor.setTableName(modevType.getTablename());
        sensor.setTypeName(modevType.getMc());
        Zsb zsb = zsbService.detail(sensor.getZsbId());
        sensor.setZsbName(zsb.getMc());
        sensor.setJgName(zsb.getJgName());
    }


    @Override
    public Page<NSensor> list(Integer typeId, int pageNum, int pageSize) throws Exception {
        PageRequest request = PageRequest.of(pageNum - 1, pageSize);
        Specification<NSensor> specification = (root, query, builder) -> {
            Predicate predicate = builder.conjunction();
            if (typeId != null) {
                predicate.getExpressions().add(builder.equal(root.get("typeId"), typeId));
            }
            query.orderBy(builder.asc(root.get("id")));
            return predicate;
        };
        Page<NSensor> result = repository.findAll(specification, request);
        this.fillOtherNames(result.getContent());
        return result;
    }

    @Override
    public NSensor add(NSensor item) throws Exception {
        item.setId(null);
        item.setStatus(Constants.NORMAL);
        repository.save(item);
        if (item.getDevId() == null) {
            item.setDevId(item.getId());
            repository.save(item);
        }
        return item;
    }

    @Override
    public void update(NSensor item) throws Exception {
        repository.save(item);
    }

    @Override
    public void batchUpdate(SensorUpdateModel model) throws Exception {
        zsbService.detail(model.getZsbId());
        for (Integer id : model.getIdList()) {
            Optional<NSensor> optional = repository.findById(id);
            if (!optional.isPresent()) {
                throw new BusinessException("未找到该装置" + id);
            }
            NSensor sensor = optional.get();
            sensor.setZsbId(model.getZsbId());
        }
    }

    @Override
    public void delete(Integer id) throws Exception {
        List<WarnRule> list = ruleRepository.findBySensorId(id);
        if (!CollectionUtils.isEmpty(list)) {
            throw new BusinessException("该监测装置已配置告警规则，请先删除对应的规则后再来操作");
        }
        repository.deleteById(id);
    }

    @Override
    public NSensor detail(Integer id) throws Exception {
        Optional<NSensor> optional = repository.findById(id);
        if (!optional.isPresent()) {
            return null;
        }
        NSensor sensor = optional.get();
        this.fillOtherName(sensor);
        return sensor;
    }

    @Override
    public SensorDetail<Map<String, Object>> getDetail(ConditionModel model) throws Exception {
        NSensor sensor;
        if (model.isTimeAsc() && model.getStartTime() == null) {
            throw new BusinessException("升序情况下开始时间不能为空");
        }
        if (model.getId() != null) {
            Optional<NSensor> optional = repository.findById(model.getId());
            if (!optional.isPresent()) {
                throw new BusinessException("未找到该装置id=" + model.getId());
            }
            sensor = optional.get();
        } else if (model.getDevId() != null) {
            List<NSensor> list = repository.findByDevId(model.getDevId());
            if (CollectionUtils.isEmpty(list)) {
                throw new BusinessException("未找到该装置devId=" + model.getDevId());
            } else if (list.size() > 1) {
                throw new BusinessException("存在相同devId=" + model.getDevId() + "的多个装置,请先修正监测装置数据");
            }
            sensor = list.get(0);
        } else {
            throw new BusinessException("缺少id或者eqmid信息");
        }

        if (sensor.getTypeId() == null) {
            throw new BusinessException("该装置缺少类型id信息");
        }
        if (sensor.getDevId() == null) {
            throw new BusinessException("该装置缺少dev_id信息");
        }
        this.fillOtherName(sensor);
        if (StringUtils.isBlank(sensor.getTableName())) {
            throw new BusinessException("该装置类型(" + sensor.getTypeName() + ")缺少table_name信息");
        }
        List<ModevTypePoint> points = modevTypePointService.listAll(sensor.getTypeId());
        if (CollectionUtils.isEmpty(points)) {
            throw new BusinessException("该装置类型(" + sensor.getTypeName() + ")未配置属性点信息");
        }

        // 获取数据
        SensorDetail<Map<String, Object>> result = this.getData(sensor, points, model);
        return result;
    }

    public SensorDetail<Map<String, Object>> getData(NSensor sensor, List<ModevTypePoint> points, ConditionModel model) throws Exception {
        List<ModevTypePoint> pointList = new ArrayList<>();
        for (ModevTypePoint point : points) {
            if (StringUtils.isNotBlank(point.getField())) {
                pointList.add(point);
            }
        }

        SensorDetail<Map<String, Object>> result = new SensorDetail();
        result.setSensor(sensor);

        OnePage<Map<String, Object>> page = dataService.getData(sensor.getTableName(), sensor.getDevId(), pointList, model);
        result.initFrom(page);

        for (ModevTypePoint point : pointList) {
            List<Object> dataList = new ArrayList<>();
            for (Map<String, Object> item : result.getContent()) {
                Object value = item.get(point.getField());
                dataList.add(value);
            }
            point.setData(dataList);
        }
        result.setPoints(pointList);
        return result;
    }

    @Override
    public void bindicd(Integer id, Integer icdid) throws Exception {
        NSensor entity = repository.findById(id).orElse(null);
        if (entity != null) {
            entity.setIcdId(icdid);
            repository.save(entity);
        } else {
            throw new BusinessException("未找到该传监测装置");
        }
    }

    @Async
    @Override
    public void importFrom(Collection<NSensor> collection) {
        for (NSensor item : collection) {
            this.importOne(item);
        }
    }

    @Override
    public void importOne(NSensor item) {
        List<NSensor> list = repository.findBySensorCode(item.getSensorCode());
        if (!CollectionUtils.isEmpty(list)) {
            item.setId(list.get(0).getId());
        }
        repository.save(item);

        Integer sensor103Id = null;
        N103Sensor n103Sensor = item.getN103Sensor();
        if (n103Sensor != null) {
            n103Sensor.setNsensorId(item.getId());
            n103SensorService.importOne(n103Sensor);
            sensor103Id = n103Sensor.getId();
        }

        // 清空旧的全部属性
        pointService.clearAll(item.getId(), sensor103Id);

        List<NPoint> points = item.getPoints();
        if (points != null) {
            for (NPoint point : points) {
                point.setSensorId(item.getId());
                if (point.getN103Point() != null) {
                    point.getN103Point().setSensor103Id(sensor103Id);
                }
                pointService.importOne(point);
            }
        }
    }

    @Override
    public String importFromModev() throws Exception {
        int success = 0;
        int skip = 0;
        List<Modev> list = modevRepository.findAll();
        List<String> warnList = new ArrayList<>();
        for (Modev item : list) {
            NSensor sensor = item.transform();
            List<I2relation> i2relations = i2relationRepository.findByEqmid(item.getId());
            if (!CollectionUtils.isEmpty(i2relations)) {
                I2relation i2relation = i2relations.get(0);
                sensor.setEquipmentId(i2relation.getEquipmentid());
                sensor.setSensorCode(i2relation.getSensorid());
                sensor.setPhase(i2relation.getPhase());
                if (i2relations.size() > 1) {
                    String str = "eqmid=" + item.getId() + "的I2relation数据存在多条，需要人工再次校对编号和相位";
                    warnList.add(str);
                }
            }
            List<NSensor> slist = repository.findByDevId(sensor.getDevId());
            if (CollectionUtils.isEmpty(slist)) {
                this.add(sensor);
                success++;
            } else {
                String str = "eqmid=" + item.getId() + "的已存在跳过";
                warnList.add(str);
                skip++;
            }
        }
        String str = "成功导入" + success + "个，跳过" + skip + "个。";
        if (warnList.size() > 0) {
            str = str + warnList.stream().collect(Collectors.joining(";"));
        }
        return str;
    }

}
