package com.usky.cdi.service.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.usky.cdi.domain.DmpDevice;
import com.usky.cdi.mapper.DmpDeviceMapper;
import com.usky.cdi.service.config.DeviceFieldConfig;
import com.usky.cdi.service.vo.IotDataTransferVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 *
 * @author fyc
 * @email yuchuan.fu@chinausky.com
 * @date 2025/11/27
 */
@Data
@Slf4j
@Component
public class DeviceDataQuery {
    @Autowired
    private DmpDeviceMapper dmpDeviceMapper;
    @Value("${device.data.base-url}")
    private String baseUrl;
    @Value("${device.data.simulation}")
    private boolean simulation;

    @Autowired
    private DeviceFieldConfig deviceFieldConfig;

    // 定义各参数的格式化器（整数位,小数位）
    private static final DecimalFormat FORMAT_2_2 = new DecimalFormat("00.00"); // 2位整数+2位小数
    private static final DecimalFormat FORMAT_0_3 = new DecimalFormat("0.000"); // 0位整数+3位小数
    private static final DecimalFormat FORMAT_3_2 = new DecimalFormat("000.00"); // 3位整数+2位小数
    private static final DecimalFormat FORMAT_4_2 = new DecimalFormat("0000.00"); // 4位整数+2位小数

    // ========== 新增缓存相关成员变量 ==========
    // 缓存A/B/C相电流值
    private static final Map<String, Double> currentValueCache = new ConcurrentHashMap<>();
    // 缓存各相复用次数
    private static final Map<String, Integer> currentReuseCountCache = new ConcurrentHashMap<>();
    // 最大复用次数（可调整）
    private static final int MAX_REUSE_COUNT = 3;
    // 复用概率（0.5=50%概率复用，可调整）
    private static final double REUSE_PROBABILITY = 0.5;

    // 定义模拟数据范围常量
    private static final double TEMP_RANGE_MIN = 10.0;
    private static final double TEMP_RANGE_MAX = 20.0;
    private static final double HUMIDITY_RANGE_MIN = 40.0;
    private static final double HUMIDITY_RANGE_MAX = 41.0;
    private static final double OXYGEN_RANGE_MIN = 20.0;
    private static final double OXYGEN_RANGE_MAX = 21.0;
    private static final double CO2_RANGE_MIN = 480.0;
    private static final double CO2_RANGE_MAX = 490.0;
    private static final double VOLTAGE_RANGE_MIN = 220.0;
    private static final double VOLTAGE_RANGE_MAX = 230.0;
    private static final double CURRENT_RANGE_MIN = 0.0;
    private static final double CURRENT_RANGE_MAX = 1.5;
    private static final double POWER_RANGE_MIN = 1.0;
    private static final double POWER_RANGE_MAX = 20.0;
    private static final double TEMP_LINE_RANGE_MIN = 20.0;
    private static final double TEMP_LINE_RANGE_MAX = 50.0;
    private static final double LEAKAGE_CURRENT_RANGE_MIN = 50.0;
    private static final double LEAKAGE_CURRENT_RANGE_MAX = 60.0;
    private static final double FLOATING_RANGE_MIN = 0.0;
    private static final double FLOATING_RANGE_MAX = 0.5;
    private static final double FLOATING_RANGE_MIN1 = 0.0;
    private static final double FLOATING_RANGE_MAX1 = 1.0;

    private static int callCount = 0;

    /**
     * 获取指定设备类型的设备数据
     * @param transferVO 设备数据传输请求参数
     * @return 设备数据列表
     */
    public List<JSONObject> getDeviceData(IotDataTransferVO transferVO) {
        // 参数验证
        if (transferVO == null || transferVO.getDevices() == null || transferVO.getDevices().isEmpty()) {
            log.warn("获取设备数据失败：参数无效");
            return Collections.emptyList();
        }

        try {
            // 构建请求参数
            JSONObject requestBody = new JSONObject();
            List<String> deviceUuids = transferVO.getDevices().stream()
                    .map(DmpDevice::getDeviceUuid)
                    .collect(Collectors.toList());
            requestBody.put("deviceuuid", deviceUuids);

            log.debug("请求设备数据接口，设备数量：{}", deviceUuids.size());
            String response = HttpClientUtils.doPostJson(baseUrl, requestBody.toJSONString());
            log.warn("接口返回数据：{}", response);

            List<JSONObject> resultList = parseResponseData(response, transferVO.getDeviceType(), transferVO.getDevices());

            // 若返回数据为空且开启模拟模式，则生成模拟数据
            if (resultList.isEmpty() && simulation) {
                log.info("接口返回数据为空，生成模拟数据，设备类型：{}", transferVO.getDeviceType());
                resultList = generateSimulationData(transferVO.getDeviceType(), transferVO.getDevices());
            } else if (resultList.size() < transferVO.getDevices().size()) {
                log.warn("接口返回数据数量与请求数量不一致，设备类型：{}", transferVO.getDeviceType());

                // 获取返回数据中的device_id集合
                Set<String> returnedDeviceIds = resultList.stream()
                        .map(data -> data.getString("device_id"))
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());

                // 获取请求中devices的device_id集合
                Map<String, DmpDevice> requestDeviceMap = transferVO.getDevices().stream()
                        .filter(device -> device.getDeviceId() != null)
                        .collect(Collectors.toMap(DmpDevice::getDeviceId, device -> device));

                // 找出返回数据中缺少的device_id
                List<String> missingDeviceIds = requestDeviceMap.keySet().stream()
                        .filter(deviceId -> !returnedDeviceIds.contains(deviceId))
                        .collect(Collectors.toList());

                if (!missingDeviceIds.isEmpty() && simulation) {
                    log.info("发现缺少的设备数据，生成模拟数据，设备数量：{}", missingDeviceIds.size());
                    // 为缺少的设备生成模拟数据
                    List<DmpDevice> missingDevices = missingDeviceIds.stream()
                            .map(requestDeviceMap::get)
                            .collect(Collectors.toList());
                    List<JSONObject> missingSimulationData = generateSimulationData(transferVO.getDeviceType(), missingDevices);
                    // 将模拟数据与返回数据结合
                    resultList.addAll(missingSimulationData);
                }

                // 校验结合后的数据是否与请求的device_id一一对应
                Set<String> combinedDeviceIds = resultList.stream()
                        .map(data -> data.getString("device_id"))
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());

                if (combinedDeviceIds.size() != transferVO.getDevices().size()) {
                    log.warn("数据整合后仍存在缺失，请求设备数量：{}，返回设备数量：{}",
                            transferVO.getDevices().size(), combinedDeviceIds.size());
                } else {
                    log.debug("数据整合完成，设备数量与请求一致：{}", combinedDeviceIds.size());
                }
            }

            return resultList;
        } catch (Exception e) {
            log.error("获取设备数据失败：{}", e.getMessage(), e);
            // 异常情况下若开启模拟模式，则生成模拟数据
            if (simulation) {
                log.info("接口调用异常，生成模拟数据，设备类型：{}", transferVO.getDeviceType());
                return generateSimulationData(transferVO.getDeviceType(), transferVO.getDevices());
            }
            return Collections.emptyList();
        }
    }

    /**
     * 解析接口响应数据，提取指定字段
     * @param responseJson 接口响应JSON字符串
     * @param deviceType 设备类型
     * @param devices 设备列表
     * @return 解析后的设备数据列表
     */
    private List<JSONObject> parseResponseData(String responseJson, Integer deviceType, List<DmpDevice> devices) {
        List<JSONObject> resultList = new ArrayList<>();
        if (responseJson == null || responseJson.trim().isEmpty()) {
            log.warn("接口响应数据为空");
            return resultList;
        }

        try {
            // 构建设备UUID到ID的映射，过滤掉deviceUuid为null的设备
            Map<String, String> deviceUuidToIdMap = devices.stream()
                    .filter(device -> device.getDeviceUuid() != null)
                    .collect(Collectors.toMap(DmpDevice::getDeviceUuid, DmpDevice::getDeviceId));

            JSONObject responseObj = JSON.parseObject(responseJson);

            // 检查响应状态
            String status = responseObj.getString("status");
            String code = responseObj.getString("code");

            if (!"SUCCESS".equals(status) || !"0".equals(code)) {
                log.warn("接口返回失败：状态={}, 错误码={}, 错误信息={}", status, code, responseObj.getString("msg"));
                return resultList;
            }

            JSONArray dataArray = responseObj.getJSONArray("data");
            if (dataArray == null || dataArray.isEmpty()) {
                log.debug("接口响应数据为空数组");
                return resultList;
            }

            List<String> targetFields = getTargetFieldsByDeviceType(deviceType);

            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject deviceData = dataArray.getJSONObject(i);
                if (deviceData == null) {
                    continue;
                }

                JSONObject metrics = deviceData.getJSONObject("metrics");
                String deviceUuid = deviceData.getString("deviceuuid");

                if (metrics == null || deviceUuid == null) {
                    continue;
                }

                JSONObject targetData = new JSONObject();
                boolean hasValidData = false;

                // 提取目标字段数据
                for (String field : targetFields) {
                    Object value = metrics.get(field);
                    if (value != null) {
                        targetData.put(field, value);
                        hasValidData = true;
                    }
                }

                // 添加设备标识信息
                targetData.put("deviceuuid", deviceUuid);
                String deviceId = deviceUuidToIdMap.get(deviceUuid);
                targetData.put("device_id", deviceId);

                if (hasValidData) {
                    resultList.add(targetData);
                }
            }

            log.debug("解析接口响应数据完成，有效设备数据数量：{}", resultList.size());
            return resultList;
        } catch (Exception e) {
            log.error("解析接口响应数据失败：{}", e.getMessage(), e);
            return Collections.emptyList();
        }
    }

    /**
     * 根据设备类型获取目标字段（自动包含time）
     * @param deviceType 设备类型
     * @return 目标字段列表
     */
    private List<String> getTargetFieldsByDeviceType(Integer deviceType) {
        if (deviceType == null) {
            log.warn("获取目标字段失败：设备类型为空");
            return Collections.singletonList("realtime");
        }

        String fieldsStr = deviceFieldConfig.deviceFieldMapping().get(deviceType.toString());
        if (fieldsStr == null || fieldsStr.trim().isEmpty()) {
            log.warn("获取目标字段失败：设备类型{}对应的字段映射不存在", deviceType);
            return Collections.singletonList("realtime");
        }

        List<String> fields = Arrays.stream(fieldsStr.split(","))
                .map(String::trim)
                .filter(field -> !field.isEmpty())
                .collect(Collectors.toList());

        // 确保包含时间字段
        if (!fields.contains("realtime")) {
            fields.add("realtime");
        }

        return fields;
    }

    /**
     * 生成模拟数据（按指定精度格式化）
     * @param deviceType 设备类型
     * @param devices 设备列表
     * @return 模拟数据列表
     */
    private List<JSONObject> generateSimulationData(Integer deviceType, List<DmpDevice> devices) {

        Map<String, Double> stringDoubleMap = WeatherFetcher.fetchWeather();

        List<JSONObject> simulationList = new ArrayList<>();
        long currentTime = System.currentTimeMillis();

        for (DmpDevice device : devices) {
            JSONObject simulationData = new JSONObject();
            simulationData.put("realtime", currentTime);
            simulationData.put("device_id", device.getDeviceId());

            if (deviceType == null) {
                log.warn("生成模拟数据失败：设备类型为空，设备ID：{}", device.getId());
                continue;
            }

            switch (deviceType) {
                // 单一温度传感器（707）
                case 707:
                    double temp707 = 0.0;
                    if (stringDoubleMap.isEmpty()) {
                        temp707 = ThreadLocalRandom.current().nextDouble(TEMP_RANGE_MIN, TEMP_RANGE_MAX);
                    } else {
                        double floating = ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN, FLOATING_RANGE_MAX);
                        temp707 = stringDoubleMap.get("temperature") + 0.5 + floating;
                    }
                    simulationData.put("wd", formatNumber(temp707, FORMAT_2_2));
                    break;

                // 单一湿度传感器（708）
                case 708:
                    simulationData.put("sd", formatNumber(ThreadLocalRandom.current().nextDouble(HUMIDITY_RANGE_MIN, HUMIDITY_RANGE_MAX), FORMAT_2_2));
                    break;

                // 单一氧气传感器（709）
                case 709:
                    double o2709 = ThreadLocalRandom.current().nextDouble(OXYGEN_RANGE_MIN, OXYGEN_RANGE_MAX);
                    simulationData.put("o2", formatNumber(o2709, FORMAT_2_2));
                    break;

                // 单一二氧化碳传感器（710）
                case 710:
                    double co2710 = ThreadLocalRandom.current().nextDouble(CO2_RANGE_MIN, CO2_RANGE_MAX);
                    simulationData.put("co2", formatNumber(co2710, FORMAT_0_3));
                    break;

                // 单一一氧化碳传感器（711）
                case 711:
                    simulationData.put("co", 0);
                    break;

                // 水浸（702）
                case 702:
                    simulationData.put("leach_status", 0);
                    break;

                // 人员统计（703）
                case 703:
                    simulationData.put("sensorValue", 0);
                    break;

                // 电气火灾（704）
                case 704:
                    // A/B/C相电压：3位整数+2位小数（220.00~230.00V）
                    double aVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
                    simulationData.put("aVoltage", formatNumber(aVoltage, FORMAT_3_2));
                    double bVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
                    simulationData.put("bVoltage", formatNumber(bVoltage, FORMAT_3_2));
                    double cVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
                    simulationData.put("cVoltage", formatNumber(cVoltage, FORMAT_3_2));

                    // A/B/C相电流：3位整数+2位小数（0.00~1.50A）
                    String deviceId = device.getDeviceId();
                    double aElectricity = getCurrentValue(deviceId, "a");
                    simulationData.put("aElectricity", formatNumber(aElectricity, FORMAT_3_2));
                    double bElectricity = getCurrentValue(deviceId, "b");
                    simulationData.put("bElectricity", formatNumber(bElectricity, FORMAT_3_2));
                    double cElectricity = getCurrentValue(deviceId, "c");
                    simulationData.put("cElectricity", formatNumber(cElectricity, FORMAT_3_2));

                    // 总功率：4位整数+2位小数（1.00~20.00）
                    double totalPower = (aVoltage * aElectricity + bVoltage * bElectricity + cVoltage * cElectricity) / 1000;
                    simulationData.put("totalPower", formatNumber(totalPower, FORMAT_4_2));

                    // 线温1-4：2位整数+2位小数（20.00~50.00℃）+1.0 +0.5
                    double lineTemp = 0.0;
                    if (stringDoubleMap.isEmpty()) {
                        lineTemp = ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX);
                    } else {
                        lineTemp = stringDoubleMap.get("temperature") + 1.0;
                    }
                    simulationData.put("line1TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
                    simulationData.put("Line2TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
                    simulationData.put("Line3TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
                    simulationData.put("Line4TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));

                    // 剩余电流：4位整数+2位小数（0.00~100.00mA）
                    simulationData.put("leakageCurrent", formatNumber(ThreadLocalRandom.current().nextDouble(LEAKAGE_CURRENT_RANGE_MIN, LEAKAGE_CURRENT_RANGE_MAX), FORMAT_4_2));
                    break;

                // 倾斜（712）
                case 712:
                    simulationData.put("qx", 0);
                    break;

                // 裂缝（713）
                case 713:
                    simulationData.put("cd", 0);
                    break;

                // 位移（714）
                case 714:
                    simulationData.put("wy", 0);
                    break;

                default:
                    log.warn("未知设备类型：{}，无法生成模拟数据", deviceType);
                    break;
            }

            simulationList.add(simulationData);
        }

        log.info("生成模拟数据完成，设备类型：{}，数量：{}", deviceType, simulationList.size());
        return simulationList;
    }

    /**
     * 通用数值格式化方法
     * @param value 原始数值
     * @param format 格式化器
     * @return 格式化后的字符串
     */
    private String formatNumber(double value, DecimalFormat format) {
        if (format == null) {
            return String.valueOf(value);
        }
        return format.format(value);
    }

    // ========== 获取带缓存的电流值 ==========
    private double getCurrentValue(String deviceId, String phase) {
        String cacheKey = (deviceId == null ? "dummy" : deviceId) + "_" + phase;
        int count = currentReuseCountCache.getOrDefault(cacheKey, 0);

        if (!currentValueCache.containsKey(cacheKey) || count >= MAX_REUSE_COUNT) {
            return generateNewCurrent(cacheKey);
        }

        boolean reuse = ThreadLocalRandom.current().nextDouble() < REUSE_PROBABILITY;
        if (reuse) {
            currentReuseCountCache.put(cacheKey, count + 1);
            return currentValueCache.get(cacheKey);
        } else {
            return generateNewCurrent(cacheKey);
        }
    }

    // 同步修改generateNewCurrent方法（参数改为cacheKey）
    private double generateNewCurrent(String cacheKey) {
        double newValue = ThreadLocalRandom.current().nextDouble(CURRENT_RANGE_MIN, CURRENT_RANGE_MAX);
        newValue = Math.round(newValue * 100.0) / 100.0;
        currentValueCache.put(cacheKey, newValue);
        currentReuseCountCache.put(cacheKey, 0);
        return newValue;
    }
}