package com.ho.business.controller;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONObject;
import com.ho.business.constant.DeviceTypeConstant;
import com.ho.business.entity.Device;
import com.ho.business.service.CommonService;
import com.ho.business.service.DeviceService;
import com.ho.business.vo.DeviceTransfer;
import com.ho.business.vo.req.DeviceReqVO;
import com.ho.business.vo.req.device.CommonQuery;
import com.ho.business.vo.req.device.CommonValueQuery;
import com.ho.business.vo.req.device.DeviceTreeReq;
import com.ho.business.vo.resp.DeviceRespVO;
import com.ho.business.vo.resp.EnvironmentalControlVo;
import com.ho.business.vo.resp.cabin.TemperatureVoltageNewResp;
import com.ho.business.vo.resp.point.ElecDataResp;
import com.ho.common.tools.annotation.TokenIgnore;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.datacollect.api.constant.DataCollectConstant;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author fancl
 * @desc:
 * @date 2023/5/8
 */
@RequestMapping(ContextConstant.BUSINESS + "common")
@RestController
@Api(tags = "通用设备状态查询")
@Slf4j
public class CommonController {

    @Autowired
    DeviceService deviceService;

    @Autowired
    RedisService redisService;

    @Autowired
    CommonService commonService;

    @PostMapping("newValue")
    @ApiOperation(value = "最新设备点数据")
    public DataResult<JSONObject> newValue(@RequestBody CommonValueQuery reqVo) {
        //查设备, 分为实体设备和虚拟设备,如果是实体设备,直接从对应缓存拿
        Integer stationId = reqVo.getStationId();
        Integer srcId = reqVo.getSrcId();
        List<String> cols = reqVo.getColList();
        Device device = deviceService.selectByStationIdAndSrcId(stationId, srcId);
        if (device == null) {
            throw new BusinessException(BaseResponseCode.CORRESPONDING_DEVICE_DOES_NOT_EXIST);
        }
        //返回的信息
        JSONObject retInfo = new JSONObject();
        String deviceType = device.getDeviceType();
        log.info("deviceType: {}", deviceType);
        //实体设备
        if (device.getVirtual() == 0) {
            //PCS
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.PCS)) {
                JSONObject realInfo = commonService.getRealInfo(device, cols);
                realInfo = commonService.dealPCS(realInfo, device);
                //只保留要前端请求的
                for (String col : cols) {
                    if (realInfo.containsKey(col)) {
                        retInfo.put(col, realInfo.get(col));
                    }
                }
                //加电流流向
                retInfo.put(DeviceTypeConstant.FLOW_DIRECTION, device.getFlowDirection());
            }
            //BMS
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.BMS)) {
                /*JSONObject realInfo = commonService.getRealInfo(device, cols);
                retInfo = commonService.dealBMS(realInfo, device);*/
                Map<Object, Object> infoFromRedis = commonService.getInfoFromRedis(device);
                //查询与BMS pid相同的设备
                List<DeviceRespVO> deviceRespVOS = deviceService.getListByDeviceTypeAndPid(stationId, device.getPid(), DeviceTypeConstant.TRANSMITTER);
                //筛选出温湿度仪的设备
                for (DeviceRespVO deviceRespVO : deviceRespVOS) {
                    Map<Object, Object> dealTransmitterMap = commonService.dealTransmitter(deviceRespVO);
                    infoFromRedis.putAll(dealTransmitterMap);
                }
                //查对应PCS的有功
                List<DeviceRespVO> pcsList = deviceService.getListByDeviceTypeAndPid(stationId, device.getPid(), DeviceTypeConstant.PCS);
                if (!pcsList.isEmpty()) {
                    DeviceRespVO pcsDevice = pcsList.get(0);
                    String key = pcsDevice.getDeviceType() + ":" + stationId + ":" + pcsDevice.getSrcId();
                    if (redisService.hasKey(key)) {
                        DeviceTransfer outputPower = (DeviceTransfer) redisService.hget(key, "outputPower");
                        if (outputPower != null) {
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("value", outputPower.getValue() == null ? outputPower.getValue() : outputPower.getValue().setScale(3, BigDecimal.ROUND_HALF_UP));
                            jsonObject.put("updateTime", outputPower.getUpdateTime());
                            jsonObject.put("srcId", pcsDevice.getSrcId());
                            jsonObject.put("deviceType", pcsDevice.getDeviceType());
                            infoFromRedis.put("outputPower", jsonObject);
                        }
                    }

                }
                for (String col : cols) {
                    if (infoFromRedis.containsKey(col)) {
                        Object obj = infoFromRedis.get(col);
                        if (obj != null && obj instanceof DeviceTransfer) {
                            DeviceTransfer deviceTransfer = (DeviceTransfer) obj;
                            //保留2位小数
                            if (null != deviceTransfer) {
                                BigDecimal value = deviceTransfer.getValue();
                                if (value != null) {
                                    String result = String.format("%.3f", value);
                                    deviceTransfer.setValue(new BigDecimal(result));
                                }
                            }
                            retInfo.put(col, deviceTransfer);
                        } else {
                            retInfo.put(col, obj);
                        }
                    } else {
                        DeviceTransfer deviceTransfer = new DeviceTransfer();
                        retInfo.put(col, deviceTransfer);
                    }
                }

            }
            //EMU
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.EMU)) {
                JSONObject jsonObject = new JSONObject();
                retInfo = commonService.dealEMU(device, cols);

                for (String col : cols) {
                    if (retInfo.containsKey(col)) {
                        jsonObject.put(col, retInfo.get(col));
                    } else {
                        DeviceTransfer deviceTransfer = new DeviceTransfer();
                        jsonObject.put(col, deviceTransfer);
                    }
                }
                retInfo = jsonObject;

            }
            //空调
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.AIR_CONDITION)) {
                cols.add(DeviceTypeConstant.AIRCONDITIONFAULT);
                retInfo = commonService.dealAirCondition(device, cols);
            }
            //消防设备
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.STORAGE_FIRE)) {
                //先查询所有缓存数据集
                Map<Object, Object> infoFromRedis = commonService.getInfoFromRedis(device);
                retInfo = commonService.dealFire(infoFromRedis, cols, device);

            }
            //电表
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.ELE_METER)) {
                retInfo = commonService.getRealInfo(device, cols);
            }
            //液冷
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.LIQUID_COOLING)) {
                retInfo = commonService.getLiquidCooling(device, cols);
            }
            //光储逆变器
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.OPTICAL_STORAGE)) {
             /* 储能侧电表	torageMeter
                负载侧电表	loadMeter
                并网侧电表	gridMeter*/
                //将电表三个和其他值分离出来
                List<String> collect = cols.stream().filter(i -> "torageMeter".equals(i)
                        || "loadMeter".equals(i)
                        || "gridMeter".equals(i)).collect(Collectors.toList());
                retInfo = commonService.getLiquidCooling(device, cols);
                for (String col : collect) {
                    JSONObject dd = commonService.getElecData(device, col);
                    retInfo.putAll(dd);
                }
            }
            // mppt
            if (deviceType != null && deviceType.contains(DeviceTypeConstant.MPPT)) {
                retInfo = commonService.getRealInfo(device, cols);
            }
        }
        //虚拟设备
        else if (device.getVirtual() == 1) {
            //需要查这个设备的父设备
//            Integer parentSrcId = device.getPid();
            Device parentDevice = deviceService.selectByStationIdAndSrcId(stationId, device.getFromId());
            if (parentDevice == null) {
                log.error("该虚拟设备没找到父设备");
                return DataResult.success(retInfo);
            }
            if (parentDevice.getDeviceType() == null) {
                log.error("该虚拟来源的设备没有配置设备类型");
                return DataResult.success(retInfo);
            }

            if (device.getDeviceType().contains(DeviceTypeConstant.STACK)) {
                //簇数据
                Map<String, String> colMap = cols.stream().collect(Collectors.toMap(Function.identity(), Function.identity()));
                if (cols.size() < 24 || colMap.containsKey(DataCollectConstant.BMS_POINT.clusterAlarmCodeLBit + CommonConstant.ZERO)) {
                    //因为原来的接口方法不能有效的区分，在少量改动的前提下，故而只能折中，根据参数个数来区分走什么方法
                    retInfo = commonService.getVirtualInfo(device, parentDevice, reqVo.getColList());
                } else {
                    DeviceReqVO deviceReqVO = new DeviceReqVO();
                    deviceReqVO.setStationId(stationId);
                    deviceReqVO.setPId(device.getSrcId());
                    List<DeviceRespVO> deviceList = deviceService.getList(deviceReqVO);
                    retInfo = commonService.getVirtualClusterInfo(deviceList, parentDevice, reqVo.getColList());
                }
            } else {
                //电池包数据以及其他类型的虚拟设备都走这个
                retInfo = commonService.getVirtualInfo(device, parentDevice, reqVo.getColList());
            }
        }
        //虚拟设备
        return DataResult.success(retInfo);
    }


    @ApiOperation(value = "电池包温度电压柱状图以及运行数据")
    @PostMapping("packTemperatureVoltageData")
    public DataResult<TemperatureVoltageNewResp> packTemperatureVoltageData(@RequestBody DeviceTreeReq vo) {
        TemperatureVoltageNewResp temperatureVoltageData = commonService.getTemperatureVoltageData(vo);
        return DataResult.success(temperatureVoltageData);
    }

    /**
     * 单个空调通用接口
     *
     * @param reqVo
     * @return
     */
    @PostMapping("/commonAirCondition")
    @ApiOperation(value = "空调")
    public DataResult<JSONObject> commonAirCondition(@RequestBody CommonQuery reqVo) {
        JSONObject retInfo = new JSONObject();
        Integer stationId = reqVo.getStationId();
        //先查这个站下的空调
        List<DeviceRespVO> airList = deviceService.getListByDeviceType(stationId, DeviceTypeConstant.AIR_CONDITION);
        if (!airList.isEmpty()) {
            DeviceRespVO deviceRespVO = airList.get(0);
            //在缓存里拿映射字段
            String key = deviceRespVO.getDeviceType() + ":" + stationId + ":" + deviceRespVO.getSrcId();
            if (redisService.hasKey(key)) {
                Map<Object, Object> infos = redisService.hgetall(key);
                List<String> cols = reqVo.getColList();
                for (String col : cols) {
                    if (infos.containsKey(col)) {
                        DeviceTransfer deviceTransfer = (DeviceTransfer) infos.get(col);
                        retInfo.put(col, deviceTransfer == null ? "" : NumberUtil.round(deviceTransfer.getValue(), 2));
                    } else {
                        retInfo.put(col, "");
                    }
                }

            }
        }
        return DataResult.success(retInfo);
    }

    /**
     * 单个空调通用接口
     *
     * @param reqVo
     * @return
     */
    @PostMapping("/getAirCondition")
    @ApiOperation(value = "空调新接口")
    public DataResult<JSONObject> getAirCondition(@RequestBody CommonQuery reqVo) {
        List<EnvironmentalControlVo> resultList = commonService.getAirCondition(reqVo);
        return DataResult.success(resultList);
    }


    @PostMapping("warningPCS")
    @ApiOperation(value = "215kW标准柜PCS状态字")
    public DataResult<JSONObject> warningPCS(@RequestBody CommonValueQuery reqVo) {
        JSONObject retInfo = new JSONObject();
        Integer stationId = reqVo.getStationId();
        //先查这个站下的空调
        List<DeviceRespVO> airList = deviceService.getListByDeviceType(stationId, DeviceTypeConstant.STATUS_PCS);
        if (!airList.isEmpty()) {
            DeviceRespVO deviceRespVO = airList.get(0);
            //在缓存里拿映射字段
            String key = deviceRespVO.getDeviceType() + ":" + stationId + ":" + deviceRespVO.getSrcId();
            if (redisService.hasKey(key)) {
                Map<Object, Object> infos = redisService.hgetall(key);
                List<String> cols = reqVo.getColList();
                for (String col : cols) {
                    if (infos.containsKey(col)) {
                        DeviceTransfer deviceTransfer = (DeviceTransfer) infos.get(col);
                        retInfo.put(col, deviceTransfer == null ? "" : NumberUtil.round(deviceTransfer.getValue(), 2));
                    } else {
                        retInfo.put(col, "");
                    }
                }

            }
        }
        return DataResult.success(retInfo);
    }


    @PostMapping("storageFire")
    @ApiOperation(value = "消防关联字段回显")
    public DataResult<JSONObject> getStorageFire(@RequestBody CommonValueQuery reqVo) {
        Integer stationId = reqVo.getStationId();
        Integer srcId = reqVo.getSrcId();
        List<String> cols = reqVo.getColList();
        Device device = deviceService.selectByStationIdAndSrcId(stationId, srcId);
        if (device == null) {
            throw new BusinessException(BaseResponseCode.CORRESPONDING_DEVICE_DOES_NOT_EXIST);
        }
        //返回的信息
        JSONObject retInfo = commonService.getLiquidCooling(device, cols);
        return DataResult.success(retInfo);
    }

    @PostMapping("/middlePart")
    @ApiOperation(value = "站首页的中间部分-分开的(电表总有功功率)")
    public DataResult<JSONObject> middlePart(@RequestBody CommonQuery reqVo) {
        Object middlePart = commonService.getMiddlePart(reqVo);
        return DataResult.success(middlePart);
    }

    @PostMapping("/getElec")
    @ApiOperation(value = "站首页的中间部分获取电表功率(并网侧电表以及负载负载侧电表)")
    public DataResult<List<ElecDataResp>> getElec(@RequestBody CommonQuery reqVo) {
        List<ElecDataResp> list = commonService.getElec(reqVo);
        return DataResult.success(list);
    }

    @PostMapping("/getEleMeter")
    @ApiOperation(value = "站首页的中间部分获取电表功率(储能侧电表)")
    public DataResult<JSONObject> getEleMeter(@RequestBody CommonQuery reqVo) {
        Object list = commonService.getEleMeter(reqVo);
        return DataResult.success(list);
    }

    @PostMapping("/getPVElec")
    @ApiOperation(value = "站首页的中间部分获取电表功率(光伏并网设备)")
    public DataResult<JSONObject> getPVElec(@RequestBody CommonQuery reqVo) {
        Object list = commonService.getPVElec(reqVo);
        return DataResult.success(list);
    }

    @PostMapping("/getOpticalStorage")
    @ApiOperation(value = "站首页的中间部分光储一体机(光储逆变器)")
    public DataResult<JSONObject> getOpticalStorage(@RequestBody CommonQuery reqVo) {
        Object middlePart = commonService.getOpticalStorage(reqVo);
        return DataResult.success(middlePart);
    }
}
