package com.zcxk.charge.web.service;

import com.zcxk.charge.api.dto.AlarmDetailsDto;
import com.zcxk.charge.api.dto.AppSmsDataDto;
import com.zcxk.charge.api.dto.SceneDataDto;
import com.zcxk.charge.api.dto.SceneDataForAppDto;
import com.zcxk.charge.api.vo.AlarmDetailsEntityVo;
import com.zcxk.charge.core.entity.*;
import com.zcxk.core.utils.ByteArrayUtils;
import com.zcxk.core.utils.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author Andy
**/
@Service
public class AppDataService {

    @Autowired
    private MonitorDataReportService monitorDataReportService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private AlarmDetailsService alarmDetailsService;

    @Autowired
    private DeviceAttributeSpecsService deviceAttributeSpecsService;

    @Autowired
    private DeviceParmService deviceParmService;

    @Autowired
    private SceneService sceneService;

    @Autowired
    private  DeviceAttributeService deviceAttributeService;

    /**
     * 查询场景信息
     *
     * @param typeName 类型名称(水源、水厂、泵站、售水)
     * @return
     */
    public AppSmsDataDto getProductionDataForSameMonth(String typeName) {
        // 3用水量or供水量or制水量  4 取水量or进水量 5耗电量 6耗药量
        AppSmsDataDto appSmsDataDto = new AppSmsDataDto();
        switch (typeName) {
            case "水源":
                appSmsDataDto.setIntakeWaterUsage(monitorDataReportService.getAmountCount(null, null, typeName, 4, 2).divide(BigDecimal.valueOf(10000)).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                appSmsDataDto.setPowerUsage(monitorDataReportService.getAmountCount(null, null, typeName, 5, 2).divide(BigDecimal.valueOf(10000)).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                break;
            case "水厂":
                appSmsDataDto.setIntakeWaterUsage(monitorDataReportService.getAmountCount(null, null, typeName, 3, 2).divide(BigDecimal.valueOf(10000)).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                appSmsDataDto.setPowerUsage(monitorDataReportService.getAmountCount(null, null, typeName, 5, 2).divide(BigDecimal.valueOf(10000)).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                appSmsDataDto.setDrugUsage(monitorDataReportService.getAmountCount(null, null, typeName, 6, 2).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                break;
            case "泵站":
                appSmsDataDto.setYieldWaterUsage(monitorDataReportService.getAmountCount(null, null, typeName, 3, 2).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                appSmsDataDto.setPowerUsage(monitorDataReportService.getAmountCount(null, null, typeName, 5, 2).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                break;
            case "售水":
                appSmsDataDto.setYieldWaterUsage(monitorDataReportService.getAmountCount(null, null, "水厂", 3, 2).divide(BigDecimal.valueOf(10000)).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                appSmsDataDto.setWaterUsage(monitorDataReportService.getUseAmount(null, 1).setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue());
                double amount = appSmsDataDto.getYieldWaterUsage() - appSmsDataDto.getWaterUsage();
                double defaultDouble = 0D;
                if (appSmsDataDto.getYieldWaterUsage() != null && appSmsDataDto.getYieldWaterUsage() != defaultDouble) {
                    appSmsDataDto.setWaterFeeRecoveryRate(BigDecimal.valueOf(amount).divide(BigDecimal.valueOf(appSmsDataDto.getYieldWaterUsage()),5,BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
                }
                break;
            default:
                break;
        }
        return appSmsDataDto;
    }

    /**
     * 获取总量信息
     * @param typeName
     * @param id
     * @return
     */
    public void getTotalAmount(SceneDataForAppDto returnInfo, String typeName, Long id) {
        switch (typeName) {
            case "水源":
                returnInfo.setIntakeWaterUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 4, 1).divide(BigDecimal.valueOf(10000),3,BigDecimal.ROUND_HALF_UP).doubleValue() + "万m³");
                returnInfo.setPowerUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 5, 1).divide(BigDecimal.valueOf(10000),3,BigDecimal.ROUND_HALF_UP).doubleValue() + "万kw.h");
                break;
            case "水厂":
                returnInfo.setIntakeWaterUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 4, 1).divide(BigDecimal.valueOf(10000),3,BigDecimal.ROUND_HALF_UP).doubleValue() + "万m³");
                returnInfo.setYieldWaterUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 3, 1).divide(BigDecimal.valueOf(10000),3,BigDecimal.ROUND_HALF_UP).doubleValue() + "万m³");
                returnInfo.setPowerUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 5, 1).divide(BigDecimal.valueOf(10000),3,BigDecimal.ROUND_HALF_UP).doubleValue() + "万kw.h");
                returnInfo.setDrugUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 6, 1).doubleValue() + "kg");
                break;
            case "泵站":
                returnInfo.setIntakeWaterUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 4, 1).setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue() + "m³");
                returnInfo.setYieldWaterUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 3, 1).setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue() + "m³");
                returnInfo.setPowerUsage(monitorDataReportService.getAmountCount(null, id.intValue(), typeName, 5, 1).setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue() + "kw.h");
                break;
            default:
                break;
        }
    }
    /**
     * 工艺场景(详情)
     * @param typeName 类型名称(水源、水厂、泵站、售水)
     * @param id 场景ID
     * @return
     */
    public SceneDataForAppDto getSceneDataForApp(String typeName,Long id) {
        SceneEntity sceneEntity = sceneService.findSceneByIdForApp(id);
        if (sceneEntity == null) {
            return null;
        }
        SceneDataForAppDto returnInfo = new SceneDataForAppDto();
        returnInfo.setAddress(sceneEntity.getAddress());
        returnInfo.setSceneName(sceneEntity.getSceneName());
        returnInfo.setImagePath(sceneEntity.getSceneImages().size() > 0 ? sceneEntity.getSceneImages().get(0).getImagePath() : null);
        getTotalAmount(returnInfo, typeName, id);
        List<String> deviceCodes = new ArrayList<>();
        // 查询到所有的测点信息
        Map<String, List<AlarmDetailsEntityVo>> alarms = new HashMap<>();
        Map<String, List<DeviceParmEntity>> parmMap = new HashMap<>();
        addDeviceCodes(id, deviceCodes, alarms, parmMap);
        List<SceneDataDto> sceneDataDtos = new ArrayList<>();
        for (String code : deviceCodes) {
            byte[] bytes = redisUtil.get(("sms_water_" + code).getBytes());
            // 将报警信息放置map中
            List<AlarmDetailsEntityVo> alarmVos = alarms.get(code);
            Map<Integer, AlarmDetailsEntityVo> mapAlarm = alarmVos.stream().collect(Collectors.toMap(AlarmDetailsEntityVo::getAttributeId, a -> a, (k1, k2) -> k1));
            // 将缓存中的实时数据放到map中方便进行遍历
            if (bytes != null && bytes.length > 0) {
                addSceneDataDto(bytes, returnInfo, parmMap, code, mapAlarm, sceneDataDtos);
            } else {
                for (DeviceParmEntity item : parmMap.get(code)) {
                    SceneDataDto sceneDataDto = new SceneDataDto();
                    sceneDataDto.setMonitorName(item.getAttributeName());
                    sceneDataDtos.add(sceneDataDto);
                }
            }
        }
        returnInfo.setInfos(sceneDataDtos);
        return returnInfo;
    }

    private void addSceneDataDto(byte[] bytes, SceneDataForAppDto returnInfo, Map<String, List<DeviceParmEntity>> parmMap, String deveiceCode, Map<Integer, AlarmDetailsEntityVo> mapAlarm, List<SceneDataDto> sceneDataDtos){
        MonitorDataEntity monitorDataEntity = (MonitorDataEntity) ByteArrayUtils.bytesToObject(bytes).get();
        Map<Long, MonitorDataValueEntity> map = monitorDataEntity.getDataValues().stream().collect(Collectors.toMap(MonitorDataValueEntity::getAttributeId, a -> a, (k1, k2) -> k1));
        returnInfo.setCollectDate(monitorDataEntity.getCollectDate());
        // 将缓存中的实时数据放到map中方便进行遍历
        for (DeviceParmEntity item : parmMap.get(deveiceCode)) {
            SceneDataDto sceneDataDto = new SceneDataDto();
            sceneDataDto.setMonitorName(item.getAttributeName());
            // 按属性ID查询标签值
            DeviceAttributeSpecsEntity deviceAttributeSpecsEntity = new DeviceAttributeSpecsEntity();
            deviceAttributeSpecsEntity.setAttributeId(Long.valueOf(item.getAttributeId()));
            List<DeviceAttributeSpecsEntity> deviceAttributeSpecsEntities = deviceAttributeSpecsService.findList(deviceAttributeSpecsEntity);
            if (map.containsKey(item.getAttributeId().longValue())) {
                Double value = map.get(item.getAttributeId().longValue()).getDataValue();
                if (value != null) {
                    if (deviceAttributeSpecsEntities.size() > 0) {
                        for (DeviceAttributeSpecsEntity specsEntity : deviceAttributeSpecsEntities) {
                            if (Integer.valueOf(specsEntity.getSpecsValue()) == value.intValue()) {
                                sceneDataDto.setMonitorValue(specsEntity.getSpecsName());
                            }
                        }
                    } else {
                        DeviceAttributeEntity deviceAttributeEntity = deviceAttributeService.getById(item.getAttributeId());
                        String unit = "";
                        if (deviceAttributeEntity != null && deviceAttributeEntity.getUnit() != null) {
                            unit = deviceAttributeEntity.getUnit();
                        }
                        sceneDataDto.setMonitorValue(String.format("%.3f", map.get(item.getAttributeId().longValue()).getDataValue()) + unit);
                    }
                }
            }
            // 判断是否报警
            if (mapAlarm.containsKey(item.getAttributeId().intValue())) {
                sceneDataDto.setIsAlarm(1);
            } else {
                sceneDataDto.setIsAlarm(0);
            }
            sceneDataDtos.add(sceneDataDto);
        }
    }

    private void addDeviceCodes(Long id, List<String> deviceCodes, Map<String, List<AlarmDetailsEntityVo>> alarms, Map<String, List<DeviceParmEntity>> parmMap){
        List<DeviceParmEntity> deviceParmEntities = deviceParmService.selectByScendId(id.intValue());
        for (DeviceParmEntity deviceParmEntity : deviceParmEntities) {
            if (!deviceCodes.contains(deviceParmEntity.getDeviceCode())) {
                deviceCodes.add(deviceParmEntity.getDeviceCode());
                //查询报警信息
                List<AlarmDetailsEntityVo> alarmDetailsDtos = alarmDetailsService.selectByDeviceId(id,deviceParmEntity.getDeviceId());
                alarms.put(deviceParmEntity.getDeviceCode(), alarmDetailsDtos);
                List<DeviceParmEntity> deviceParms = new ArrayList<>();
                deviceParms.add(deviceParmEntity);
                parmMap.put(deviceParmEntity.getDeviceCode(), deviceParms);
            } else {
                parmMap.get(deviceParmEntity.getDeviceCode()).add(deviceParmEntity);
            }
        }
    }
}
