package vip.xiaonuo.coldchain.modular.app.service;

/**
 * @author jackzhou
 * @version 1.0
 * @project jfcloud-coldchain
 * @description
 * @date 2024/11/17 22:30:41
 */

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.jfcloud.influxdb.flux.AggregationWindow;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
import vip.xiaonuo.coldchain.core.service.JfcloudSensorDataService;
import vip.xiaonuo.coldchain.modular.app.param.*;
import vip.xiaonuo.coldchain.modular.monitordevice.service.MonitorDeviceService;
import vip.xiaonuo.coldchain.modular.monitortarget.entity.MonitorTarget;
import vip.xiaonuo.coldchain.modular.monitortarget.param.MonitorTargetPageParam;
import vip.xiaonuo.coldchain.modular.monitortarget.param.TargetStatus;
import vip.xiaonuo.coldchain.modular.monitortarget.service.MonitorTargetService;
import vip.xiaonuo.coldchain.modular.monitortargetregion.entity.MonitorTargetRegion;
import vip.xiaonuo.coldchain.modular.monitortargetregion.service.MonitorTargetRegionService;
import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AppDeviceService {
    private final MonitorTargetService monitorTargetService;
    private final MonitorTargetRegionService monitorTargetRegionService;
    private final JfcloudSensorDataService jfcloudSensorDataService;
    private final MonitorDeviceService monitorDeviceService;

    // 模拟设备保存操作，实际应用中可能会是数据库操作
    public boolean addDevice(AppDeviceAddParam device) {
        System.out.println("设备已添加：" + device);
        return true; // 假设设备保存成功
    }

    /**
     * 监控对象列表包含温湿度监控指标--分页
     *
     * @return
     */
    public Page<AppDevice> pageDevices(AppDevicePageParam appDevicePageParam) {
        // 用于存储最终返回的 AppDevice 列表
        List<AppDevice> rlt = Lists.newArrayList();
        // 创建监控目标分页查询参数对象
        MonitorTargetPageParam monitorTargetPageParam = new MonitorTargetPageParam();
        // 设置分页参数：当前页和每页记录数
        monitorTargetPageParam.setCurrent(appDevicePageParam.getCurrent());
        monitorTargetPageParam.setSize(appDevicePageParam.getSize());
        monitorTargetPageParam.setSearchKey(appDevicePageParam.getSearchKey());
        monitorTargetPageParam.setName(appDevicePageParam.getName());
        monitorTargetPageParam.setRoomId(appDevicePageParam.getRoomId());
        monitorTargetPageParam.setOrgId(StpLoginUserUtil.getLoginUser().getOrgId());
        // 调用 monitorTargetService 查询当前用户的监控目标数据，分页结果
        Page<MonitorTarget> pageByUser = monitorTargetService.selectMonitorTargetByPage(monitorTargetPageParam);
        // 遍历监控目标分页记录
        pageByUser.getRecords().forEach(monitorTarget -> {
            // 创建新的 AppDevice 对象来存储转换后的设备信息
            AppDevice appDevice = new AppDevice();
            // 将监控目标信息复制到 AppDevice 中
            BeanUtil.copyProperties(monitorTarget, appDevice);
            appDevice.setMonitorTargetRegionList(null);
            // 获取当前监控目标的 ID，用于查询子设备数据
            String monitorTargetId = monitorTarget.getId();
            // 获取当前监控目标下的所有监控区域（子设备数据）
            List<MonitorTargetRegion> monitorTargetRegions = monitorTargetRegionService.getRegionListByTargetId(monitorTargetId);
            // 如果监控目标下存在区域（即有子设备）
            if (!monitorTargetRegions.isEmpty()) {
                // 遍历每个区域，将其转换为子设备数据，并添加到 AppDevice 的子设备列表中
                for (MonitorTargetRegion monitorTargetRegion : monitorTargetRegions) {
                    // 获取 AppDevice 的子设备列表
                    List<AppDeviceData> children = appDevice.getChildren();
                    // 如果子设备列表为空，初始化一个空的列表
                    if (children == null) {
                        children = new ArrayList<>();
                        appDevice.setChildren(children);
                    }
                    // 创建新的 AppDeviceData 对象，将监控区域数据复制到该子设备对象中
                    AppDeviceData appDeviceData = new AppDeviceData();
                    children.add(appDeviceData);
                    BeanUtil.copyProperties(monitorTargetRegion, appDeviceData);
                    String deviceCode = appDeviceData.getDeviceCode();
                    // 传感器路数
                    Integer sensorRoute = appDeviceData.getSensorRoute();
                    if (!Objects.isNull(sensorRoute) && StrUtil.isNotBlank(deviceCode)) {
                        SensorData sensorData = monitorDeviceService.queryLatestDataByDeviceIdAndRoads(deviceCode, sensorRoute);
                        if (!Objects.isNull(sensorData)) {
                            appDeviceData.setBatteryPercentage(sensorData.getBattery());
                            if (sensorData.getTime() != null) {
                                appDeviceData.setTimestamp(Date.from(sensorData.getTime()));
                            }
                            if (Objects.nonNull(sensorData.getTemperature())) {
                                float temperatureUp = Math.abs(appDeviceData.getTemperatureUp() - sensorData.getTemperature());
                                float temperatureDown = Math.abs(appDeviceData.getTemperatureDown() - sensorData.getTemperature());
                                appDeviceData.setTemperatureStatus(getDataStatus(temperatureUp, temperatureDown,
                                        appDeviceData.getTemperatureUp(), appDeviceData.getTemperatureDown(), sensorData.getTemperature()));
                            }
                            if (Objects.nonNull(sensorData.getHumidity())) {
                                float humidityUp = Math.abs(appDeviceData.getHumidityUp() - sensorData.getHumidity());
                                float humidityDown = Math.abs(appDeviceData.getHumidityDown() - sensorData.getHumidity());
                                appDeviceData.setHumidityStatus(getDataStatus(humidityUp, humidityDown,
                                        appDeviceData.getHumidityUp(), appDeviceData.getHumidityDown(), sensorData.getHumidity()));
                            }
                            if (Objects.nonNull(sensorData.getCo2())) {
                                float co2Up = Math.abs(appDeviceData.getCo2Up() - sensorData.getCo2());
                                float co2Down = Math.abs(appDeviceData.getCo2Down() - sensorData.getCo2());
                                appDeviceData.setCo2Status(getDataStatus(co2Up, co2Down,
                                        appDeviceData.getCo2Up(), appDeviceData.getCo2Down(), sensorData.getCo2()));
                            }
                            appDeviceData.setHumidity(sensorData.getHumidity());
                            appDeviceData.setTemperature(sensorData.getTemperature());
                            appDeviceData.setCo2Level(sensorData.getCo2());
                            appDeviceData.setPlugInStatus(sensorData.getPlugInStatus());
                        }
                    }
                }
                // 取第一个子设备的数据来填充主体设备的电池电量和插电状态等信息
                if (!appDevice.getChildren().isEmpty()) {
                    AppDeviceData firstChild = appDevice.getChildren().get(0);
                    if (Objects.nonNull(firstChild)) {
                        appDevice.setPlugInStatus(firstChild.getPlugInStatus());
                        appDevice.setBatteryPercentage(firstChild.getBatteryPercentage());
                        appDevice.setUpdateTime(firstChild.getTimestamp());
                    }
                }
            }

            // 将转换后的设备对象添加到最终的设备列表中
            rlt.add(appDevice);
        });
        // 创建分页返回对象，设置分页信息和记录数据
        Page<AppDevice> pageResult = new Page<>();
        pageResult.setCurrent(appDevicePageParam.getCurrent()); // 当前页
        pageResult.setSize(appDevicePageParam.getSize()); // 每页记录数
        pageResult.setTotal(pageByUser.getTotal()); // 总记录数
        pageResult.setPages(pageByUser.getPages()); // 总页数
        pageResult.setRecords(rlt); // 设置当前页的设备数据
        // 返回分页结果
        return pageResult;
    }

    private static String getDataStatus(float absUp, float absDown, float up, float down, float figures) {
        if (absUp < absDown) {
            if (up > figures && absUp > 5) {
                return "0";
            } else if (up > figures && absUp <= 5) {
                return "1";
            } else {
                return "2";
            }
        } else {
            if (down < figures && absDown > 5) {
                return "0";
            } else if (down < figures && absDown <= 5) {
                return "1";
            } else {
                return "2";
            }
        }
    }


    /**
     * 分页设备关键字查询 jackzhou 25-1-7 废弃
     */
    @Deprecated
    public Page<AppDevice> pageSearchDevices(AppDevicePageParam appDevicePageParam) {
        //根据关键字搜索监控设备编码
        List<MonitorTargetRegion> regionList = monitorTargetRegionService.list(new LambdaQueryWrapper<>(MonitorTargetRegion.class)
                .like(MonitorTargetRegion::getSensorCode, appDevicePageParam.getSearchKey())
                .eq(MonitorTargetRegion::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        Map<String, List<MonitorTargetRegion>> regionTargetMap = regionList.stream().collect(Collectors.groupingBy(MonitorTargetRegion::getMonitorTargetId));

        //根据监控设备 或 关键字搜索监控对象
        Page<MonitorTarget> targetPage = monitorTargetService.page(new Page<>(appDevicePageParam.getCurrent(), appDevicePageParam.getSize()),
                new LambdaQueryWrapper<>(MonitorTarget.class)
                        .eq(StrUtil.isNotBlank(appDevicePageParam.getRoomId()), MonitorTarget::getRoomId, appDevicePageParam.getRoomId())
                        .eq(MonitorTarget::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE)
                        .and(x -> x.like(MonitorTarget::getName, appDevicePageParam.getSearchKey())
                                .or(CollUtil.isNotEmpty(regionTargetMap.keySet()), y -> y.in(MonitorTarget::getId, regionTargetMap.keySet())))
                        .orderByAsc(MonitorTarget::getStatus, MonitorTarget::getName));

        // 用于存储最终返回的 AppDevice 列表
        List<AppDevice> rlt = Lists.newArrayList();

        // 遍历监控目标分页记录
        targetPage.getRecords().forEach(monitorTarget -> {
            // 创建新的 AppDevice 对象来存储转换后的设备信息
            AppDevice appDevice = new AppDevice();
            // 将监控目标信息复制到 AppDevice 中
            BeanUtil.copyProperties(monitorTarget, appDevice);
            appDevice.setMonitorTargetRegionList(null);
            // 获取当前监控目标的 ID，用于查询子设备数据
            String monitorTargetId = monitorTarget.getId();

            // 如果是用监控设备编码查询到的，则只展示对应的监控设备；如果是用关键字查询到的，则展示该监控目标下的所有子设备
            List<MonitorTargetRegion> monitorTargetRegions = regionTargetMap.getOrDefault(monitorTargetId,
                    monitorTargetRegionService.getRegionListByTargetId(monitorTargetId));

            if (CollUtil.isEmpty(monitorTargetRegions)) {
                rlt.add(appDevice);
                return;
            }

            // 遍历每个区域，将其转换为子设备数据，并添加到 AppDevice 的子设备列表中
            for (MonitorTargetRegion monitorTargetRegion : monitorTargetRegions) {
                // 获取 AppDevice 的子设备列表
                List<AppDeviceData> children = appDevice.getChildren();
                // 如果子设备列表为空，初始化一个空的列表
                if (children == null) {
                    children = new ArrayList<>();
                    appDevice.setChildren(children);
                }
                // 创建新的 AppDeviceData 对象，将监控区域数据复制到该子设备对象中
                AppDeviceData appDeviceData = new AppDeviceData();
                children.add(appDeviceData);
                BeanUtil.copyProperties(monitorTargetRegion, appDeviceData);
                String deviceCode = appDeviceData.getDeviceCode();
                // 传感器路数
                Integer sensorRoute = appDeviceData.getSensorRoute();
                if (!Objects.isNull(sensorRoute) && StrUtil.isNotBlank(deviceCode)) {
                    SensorData sensorData = monitorDeviceService.queryLatestDataByDeviceIdAndRoads(deviceCode, sensorRoute);
                    if (!Objects.isNull(sensorData)) {
                        appDeviceData.setBatteryPercentage(sensorData.getBattery());
                        if (sensorData.getTime() != null) {
                            appDeviceData.setTimestamp(Date.from(sensorData.getTime()));
                        }
                        appDeviceData.setHumidity(sensorData.getHumidity());
                        appDeviceData.setTemperature(sensorData.getTemperature());
                        appDeviceData.setCo2Level(sensorData.getCo2());
                        appDeviceData.setPlugInStatus(sensorData.getPlugInStatus());
                    }
                }
            }
            // 取第一个子设备的数据来填充主体设备的电池电量和插电状态等信息
            if (!appDevice.getChildren().isEmpty()) {
                AppDeviceData firstChild = appDevice.getChildren().get(0);
                if (Objects.nonNull(firstChild)) {
                    appDevice.setPlugInStatus(firstChild.getPlugInStatus());
                    appDevice.setBatteryPercentage(firstChild.getBatteryPercentage());
                    appDevice.setUpdateTime(firstChild.getTimestamp());
                }
            }

            // 将转换后的设备对象添加到最终的设备列表中
            rlt.add(appDevice);
        });

        // 创建分页返回对象，设置分页信息和记录数据
        Page<AppDevice> pageResult = new Page<>();
        pageResult.setCurrent(appDevicePageParam.getCurrent()); // 当前页
        pageResult.setSize(appDevicePageParam.getSize()); // 每页记录数
        pageResult.setTotal(targetPage.getTotal()); // 总记录数
        pageResult.setPages(targetPage.getPages()); // 总页数
        pageResult.setRecords(rlt); // 设置当前页的设备数据

        // 返回分页结果
        return pageResult;
    }


    /**
     * 获取设备总数
     *
     * @param keyword
     * @param roomId
     * @return
     */
    public DeviceStatus getDeviceStatus(String keyword, String roomId) {
        TargetStatus targetCount = monitorTargetService.getTargetCount(keyword, roomId);
        DeviceStatus deviceStatus = new DeviceStatus();
        BeanUtil.copyProperties(targetCount, deviceStatus);
        return deviceStatus;
    }

    public SensorEchartDataResult queryDataByDeviceIdAndRoads(AppDeviceQueryParams appDeviceQueryParams) {
        Assert.notNull(appDeviceQueryParams, "appDeviceQueryParams cannot be null");
        // 获取用户选择的聚合维度，优先使用用户选择的聚合维度，如果没有选择则根据时间范围计算
        AggregationWindow window = null;
        String aggregationWindow = appDeviceQueryParams.getAggregationWindow();
        if (StrUtil.isBlank(aggregationWindow)) {
            window = AggregationWindow.determineAggregationWindow(appDeviceQueryParams.getStartTime(), appDeviceQueryParams.getEndTime());
        } else {
            // 如果用户选择了聚合维度，但不在枚举中，使用默认的聚合窗口
            window = AggregationWindow.fromString(aggregationWindow);
        }
        // 查找监控目标区域
        MonitorTargetRegion monitorTarget = monitorTargetRegionService.findOneByDeviceCodeAndSensorNo(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());
        // 如果监控目标区域为空，直接返回空的结果
        if (Objects.isNull(monitorTarget)) {
            return getEmptyResult();
        }
        String sensorType = monitorTarget.getSensorType();
        // 如果传感器类型为空，直接返回空的结果
        if (StrUtil.isBlank(sensorType)) {
            return getEmptyResult();
        }
        // 定义传感器类型与数据类型的映射关系
        Map<String, String> sensorMapping = Map.of("w", "temperature", // 温度
                "s", "humidity",    // 湿度
                "c", "co2"          // 二氧化碳
        );
        // 创建结果对象
        SensorEchartDataResult result = new SensorEchartDataResult();
        // 遍历传感器类型映射
        AggregationWindow finalWindow1 = window;
        sensorMapping.forEach((key, dataType) -> {
            // 如果传感器类型包含对应的字符
            if (sensorType.toLowerCase().contains(key)) {
                // 获取相应的数据
                List<SensorData> sensorData = monitorDeviceService.queryDataByDeviceIdAndRoads(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute(), appDeviceQueryParams.getStartTime(), appDeviceQueryParams.getEndTime(), dataType, finalWindow1);
                // 处理数据并设置到对应的字段
                SensorEchartData echartData = SensorDataTransformer.processSensorData(sensorData, dataType, finalWindow1);
                if ("temperature".equals(dataType)) {
                    echartData.setUp(monitorTarget.getTemperatureUp());
                    echartData.setDown(monitorTarget.getTemperatureDown());
                    result.setTemperature(echartData);

                } else if ("humidity".equals(dataType)) {
                    echartData.setUp(monitorTarget.getHumidityUp());
                    echartData.setDown(monitorTarget.getHumidityDown());
                    result.setHumidity(echartData);
                } else if ("co2".equals(dataType)) {
                    echartData.setUp(monitorTarget.getCo2Up());
                    echartData.setDown(monitorTarget.getCo2Down());
                    result.setCo2(echartData);
                }
            }
        });
        return result;
    }

    // 辅助方法：返回空的结果对象
    private SensorEchartDataResult getEmptyResult() {
        return new SensorEchartDataResult(); // 默认构造一个空的结果对象
    }


    public Boolean updateDeviceAlarm(AppDeviceAlarmParam appDeviceAlarmParam) {
        Assert.notNull(appDeviceAlarmParam, "appDeviceAlarmParam cannot be null");
        MonitorTargetRegion monitorTargetRegion = monitorTargetRegionService.getById(appDeviceAlarmParam.getMonitorTargetRegionId());
        if (Objects.isNull(monitorTargetRegion)) {
            return Boolean.FALSE;
        }
        updateField(appDeviceAlarmParam::getTemperatureDown, monitorTargetRegion::setTemperatureDown);
        updateField(appDeviceAlarmParam::getTemperatureUp, monitorTargetRegion::setTemperatureUp);
        updateField(appDeviceAlarmParam::getHumidityDown, monitorTargetRegion::setHumidityDown);
        updateField(appDeviceAlarmParam::getHumidityUp, monitorTargetRegion::setHumidityUp);
        updateField(appDeviceAlarmParam::getCo2Down, monitorTargetRegion::setCo2Down);
        updateField(appDeviceAlarmParam::getCo2Up, monitorTargetRegion::setCo2Up);
        return monitorTargetRegionService.updateById(monitorTargetRegion);
    }

    private <V> void updateField(Supplier<V> getter, Consumer<V> setter) {
        V value = getter.get();
        if (value != null) {
            setter.accept(value);
        }
    }

    public SensorIndicator indicators(AppIndicatorQueryParams appDeviceQueryParams) {
        // 假设上月数据
        long lastMonthCollected = jfcloudSensorDataService.getLastMonthDataCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());
        long lastMonthWarnings = jfcloudSensorDataService.getLastMonthAlarmCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());   // 上月预警总数
        long lastMonthAbnormal = jfcloudSensorDataService.getLastMonthOfflineCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());   // 上月异常总数
        // 计算本月数据
        long totalCollected = jfcloudSensorDataService.getCurrentMonthDataCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());
        long totalWarnings = jfcloudSensorDataService.getCurrentMonthAlarmCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());   // 同比减少5%
        long totalAbnormal = jfcloudSensorDataService.getCurrentMonthOfflineCount(appDeviceQueryParams.getSensorCode(), appDeviceQueryParams.getSensorRoute());
        ;   // 同比增长10%
        // 创建响应对象
        SensorIndicator response = new SensorIndicator();
        response.setTotalCollected(totalCollected);
        response.setTotalWarnings(totalWarnings);
        response.setTotalAbnormal(totalAbnormal);
        //计算相对上个月的半分比
        response.setCollectedChange(formatChange(calculateChange(lastMonthCollected, totalCollected)));
        response.setWarningsChange(formatChange(calculateChange(lastMonthWarnings, totalWarnings)));
        response.setAbnormalChange(formatChange(calculateChange(lastMonthAbnormal, totalAbnormal)));
        return response;
    }

    // 计算百分比变化的辅助方法
    private double calculateChange(long lastMonthValue, long currentMonthValue) {
        if (lastMonthValue == 0) {
            return currentMonthValue > 0 ? 100.0 : 0.0;  // 如果上月数据为0，本月有数据则变化为100%，否则为0%
        }
        return ((double) (currentMonthValue - lastMonthValue) / lastMonthValue) * 100;
    }

    // 格式化百分比变化（添加正负符号并限制小数位数）
    private String formatChange(double change) {
        if (change > 0) {
            return String.format("+%.2f%%", change);
        } else if (change < 0) {
            return String.format("%.2f%%", change);
        } else {
            return "0.00%";
        }
    }

    public Boolean updateDeviceInfo(AppDeviceUpdateParam appDeviceAlarmParam) {
        MonitorTargetRegion monitorTargetRegion = monitorTargetRegionService.getById(appDeviceAlarmParam.getMonitorTargetRegionId());
        if (monitorTargetRegion == null) {
            return false;
        }
        if (StrUtil.isNotBlank(appDeviceAlarmParam.getName())) {
            monitorTargetRegion.setName(appDeviceAlarmParam.getName());
        }
        monitorTargetRegion.setIgnoreStartTime(appDeviceAlarmParam.getIgnoreStartTime());
        monitorTargetRegion.setIgnoreEndTime(appDeviceAlarmParam.getIgnoreEndTime());
        monitorTargetRegion.setAlarmUsers(appDeviceAlarmParam.getAlarmUsers());
        monitorTargetRegion.setDeviceOfflineAlarm(appDeviceAlarmParam.getDeviceOfflineAlarm());
        return monitorTargetRegionService.updateById(monitorTargetRegion);
    }
}
