package cn.wise.sc.energy.power.plant.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.wise.sc.energy.power.plant.business.domain.CharacterParamInfo;
import cn.wise.sc.energy.power.plant.business.domain.DeviceInfo;
import cn.wise.sc.energy.power.plant.business.domain.UnitInfo;
import cn.wise.sc.energy.power.plant.business.domain.vo.CharacterParamInfoVo;
import cn.wise.sc.energy.power.plant.business.domain.vo.DeviceInfoVo;
import cn.wise.sc.energy.power.plant.business.domain.vo.EntityVo;
import cn.wise.sc.energy.power.plant.business.domain.vo.UnitInfoVo;
import cn.wise.sc.energy.power.plant.business.opentsdb.OpentsdbOkHttpClient;
import cn.wise.sc.energy.power.plant.business.opentsdb.bean.QueryExt;
import cn.wise.sc.energy.power.plant.business.opentsdb.bean.QueryRequestExt;
import cn.wise.sc.energy.power.plant.business.repository.UnitInfoRepository;
import cn.wise.sc.energy.power.plant.business.service.ICharacterParamService;
import cn.wise.sc.energy.power.plant.business.service.IDeviceInfoService;
import cn.wise.sc.energy.power.plant.common.core.exception.ResponseEnum;
import lombok.extern.slf4j.Slf4j;
import net.opentsdb.client.api.query.response.QueryResponse;
import net.opentsdb.client.bean.Aggregator;
import net.opentsdb.client.bean.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @description: 设备信息服务层实现
 * @author: qh
 * @create: 2020-07-14 16:38
 **/
@Slf4j
@Service
public class DeviceInfoServiceImpl extends BaseServiceImpl<String, DeviceInfo> implements IDeviceInfoService {

    final
    UnitInfoRepository unitInfoRepository;
    @Autowired
    ICharacterParamService iCharacterParamService;

    public DeviceInfoServiceImpl(UnitInfoRepository unitInfoRepository) {
        this.unitInfoRepository = unitInfoRepository;
    }

    @Override
    public List<EntityVo> getDeviceInfoByPlantCode(final String plantId) {

        ResponseEnum.LICENCE_NOT_FOUND.assertNotEmpty(plantId);

        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setPlantId(plantId);

        List<DeviceInfo> all = this.repository.findAll(Example.of(deviceInfo));
        List<EntityVo> rts = new ArrayList<>(all.size());
        for (DeviceInfo deviceInfo1 : all) {
            EntityVo entityVo = new DeviceInfoVo();
            BeanUtil.copyProperties(deviceInfo1, entityVo);
            rts.add(entityVo);
        }

        return rts;
    }

    @Override
    public List<DeviceInfoVo> getDeviceAndUnitByPlantCode(final String plantId) {

        ResponseEnum.LICENCE_NOT_FOUND.assertNotEmpty(plantId);
        //获取设备
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setPlantId(plantId);
        List<DeviceInfo> deviceInfos = this.repository.findAll(Example.of(deviceInfo));
        if (deviceInfos.size() == 0) {
            return null;
        }
        Set<String> deviceInfoIds = deviceInfos.stream().map(DeviceInfo::getDeviceId).collect(Collectors.toSet());
        //获取设备下面部件
        List<UnitInfo> unitInfos = unitInfoRepository.findAll((Specification<UnitInfo>) (root, query, criteriaBuilder) -> {
            Path<Object> deviceId = root.get("deviceId");
            CriteriaBuilder.In<Object> in = criteriaBuilder.in(deviceId);
            for (String deviceInfoId : deviceInfoIds) {
                in.value(deviceInfoId);
            }
            return in;
        });

        return buildDeviceAndUnit(deviceInfos, unitInfos);
    }

    @Override
    public List<DeviceInfoVo> getDeviceUnitAndCharacterPlantCode(final String plantId) {

        //获取到设备和设备下的部件
        List<DeviceInfoVo> deviceInfoVos = getDeviceAndUnitByPlantCode(plantId);
        //用部件去获取测点
        List<String> unitCodeIds = new ArrayList<>();
        deviceInfoVos.forEach(arg -> {
            arg.getUnitInfoVos().forEach(opt -> {
                unitCodeIds.add(opt.getUnitCodeId());
            });
        });
        List<CharacterParamInfoVo> characterParamInfoVos = iCharacterParamService.getCharactersByUnitCodeIds(unitCodeIds);

        deviceInfoVos.forEach(arg -> {
            arg.getUnitInfoVos().forEach(opt -> {
                List<CharacterParamInfoVo> theCharacterParamInfoVos = new ArrayList<>();
                opt.setCharacters(theCharacterParamInfoVos);
                characterParamInfoVos.forEach(param -> {
                    if (opt.getUnitCodeId().equals(param.getUnitCodeId())) {
                        opt.getCharacters().add(param);
                    }
                });
            });
        });
        return deviceInfoVos;
    }

    @Override
    public Map<String, Integer> getDevicePowerAndActive(String deviceId) {

        //获取机组有功和功率
        QueryRequestExt queryRequestExt = QueryRequestExt.builder()
                .start("1s-ago")
                .build();

        //获取发电机转速  todo 末尾带数字代表备份
        List<CharacterParamInfo> raterCharacters =
                iCharacterParamService.getKKsCodeByDeviceAndCharacterName(deviceId, "发电机转速");
        //获取发电机有功
        List<CharacterParamInfo> powerCharacters =
                iCharacterParamService.getKKsCodeByDeviceAndCharacterName(deviceId, "燃机发电机有功功率");
        List<CharacterParamInfo> allCharacters = new ArrayList<>(raterCharacters.size() + powerCharacters.size());
        allCharacters.addAll(raterCharacters);
        allCharacters.addAll(powerCharacters);
        //获取发电机转速
        for (CharacterParamInfo characterParamInfo : allCharacters) {
            queryRequestExt.addQuery(QueryExt.builder()
                    .aggregator(Aggregator.AVG)
                    .metric(characterParamInfo.getKksCode())
                    .build());
        }

        QueryResponse response;
        try {
            response = OpentsdbOkHttpClient.query(queryRequestExt);
            if (response == null || response.getResults() == null || response.getResults().size() == 0) {
                return buildVirtualData();
            }
        } catch (IOException | URISyntaxException e) {
            buildVirtualData();
            log.error("查询发电机转速失败!");
        }

        return null;
    }

    private List<DeviceInfoVo> buildDeviceAndUnit(List<DeviceInfo> deviceInfos,
                                                  List<UnitInfo> unitInfos) {
        List<DeviceInfoVo> rts = new ArrayList<>(deviceInfos.size());
        for (DeviceInfo deviceInfo1 : deviceInfos) {
            DeviceInfoVo entityVo = new DeviceInfoVo();
            BeanUtil.copyProperties(deviceInfo1, entityVo);
            List<UnitInfo> theUnitInfo = unitInfos.stream()
                    .filter(arg -> arg.getDeviceId().equals(deviceInfo1.getDeviceId()))
                    .collect(Collectors.toList());
            List<UnitInfoVo> unitInfoVos = new ArrayList<>(theUnitInfo.size());
            for (UnitInfo unitInfo : theUnitInfo) {
                unitInfoVos.add((UnitInfoVo) unitInfo.toVo());
            }
            entityVo.setUnitInfoVos(unitInfoVos);
            rts.add(entityVo);
        }
        return rts;
    }

    /**
     * 返回机组和
     *
     * @param response
     * @return
     */
    private Map<String, String> buildPowerRate(QueryResponse response,
                                               CharacterParamInfo powerCharacter,
                                               CharacterParamInfo raterCharacter) {

        List<QueryResult> results = response.getResults();
        Map<String, String> rts = new HashMap<>(2);

        return null;
    }

    /**
     * 构造假数据
     *
     * @return Map<String, String>
     */
    private Map<String, Integer> buildVirtualData() {
        Map<String, Integer> rts = new HashMap<>(2);
        rts.put("power", 0);
        rts.put("rater", 0);
        return rts;
    }

}
