import { fail } from "assert";
import { TABLENAME } from "../config/dbEnum";
import { ERRORENUM } from "../config/errorEnum";
import { selectOneDataByParam, selectDataListByParam } from "../data/findData";
import { addData } from "../data/addData";
import { BizError } from "../util/bizError";
import { controlIndoorUnit } from "./feiyiClient";
import { getRegionList } from "./region";
import { startSchedule, stopSchedule } from "../config/schedule";

/** device_state 值常量 */
const DEVICE_STATE = { NORMAL: 0, HARDWARE_FAULT: 1, COMM_FAULT: 2, OFFLINE: 3 } as const;
const OFFLINE_STATES = [DEVICE_STATE.COMM_FAULT, DEVICE_STATE.OFFLINE] as number[];

/** 判断设备是否离线（仅依据 device_state） */
function isDeviceOffline(deviceState: number): boolean {
    return OFFLINE_STATES.includes(deviceState);
}

/**
 * 联动去重缓存：记录每个区域上次下发的控制状态，避免重复调用第三方接口
 * key: regionKey, value: 上次下发的控制参数
 */
const envControlCache: Map<string, { tempSet?: number; workMode?: number; fanSpeed?: number; onOff?: number; maxTemp?: number; minTemp?: number; co2Action?: string }> = new Map();

/**
 * 将 Date 对象格式化为本地时间字符串 'YYYY-MM-DD HH:mm:ss'
 * 替代 toISOString() 避免 UTC 时区偏移问题
 */
function formatLocalTime(date: Date): string {
    const pad = (n: number) => String(n).padStart(2, '0');
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}

/**
 * 智能管控-运行分析
 * @param regionGroup 区域组（可选），如"A馆"，如果提供则返回该类型下所有区域的分析数据
 * @param regionType 区域类型（可选），如"1F"，如果提供则返回该区域的分析数据
 * @returns 大屏所需的所有指标数据
 */
export async function getRunAnalysis(regionGroup: string, regionType: string) {
    // 最终响应结果数据
    let resultAny: any = { };

    // 根据区域类型和名称筛选设备ID列表（如果提供了区域信息）
    let regionParam: any = { groups: regionGroup, "%orderAsc%": "sort_order" };
    if (regionType) {
        // regionParam.type = regionTypeKeyMap[regionType];
        regionParam.type = regionType;
    }
    let regionInfo: any = await selectDataListByParam(TABLENAME.区域表, regionParam, ["id"]);
    let regionKeys = regionInfo.data.map((r: any) => r.id);
    console.log("筛选区域Key:", regionKeys);

    // 1.1 获取所选区域三相电表及电能监测设备的用电数据（用于能耗管理）
    let powerParams: any = {device_type: { "%in%": ["三相电表", "电能监测"] }};
    if (regionGroup) {
        powerParams.region_key = { "%in%": regionKeys };
    }

    let energyDevices = await selectDataListByParam(TABLENAME.设备表, powerParams, ["device_id"]);
    let energyDeviceIds = energyDevices.data.map((d: any) => d.device_id);
    // 1.2 获取今日、昨日、本月、上月用电量
    let todayStart = new Date(); todayStart.setHours(0, 0, 0, 0);
    let todayEnd = new Date();
    let yesterdayStart = new Date(Date.now() - 86400000); yesterdayStart.setHours(0,0,0,0);
    let yesterdayEnd = new Date(Date.now() - 86400000); yesterdayEnd.setHours(23,59,59,999);
    let currentMonthStart = new Date(); currentMonthStart.setDate(1); currentMonthStart.setHours(0,0,0,0);
    let lastMonthStart = new Date(); lastMonthStart.setMonth(lastMonthStart.getMonth() - 1); lastMonthStart.setDate(1); lastMonthStart.setHours(0,0,0,0);
    let lastMonthEnd = new Date(currentMonthStart.getTime() - 1);

    // 辅助函数：查询某个时间段内的总用电量（单位 kwh）
    async function getTotalEnergy(deviceIds: string[], startTime: Date, endTime: Date): Promise<number> {
        if (deviceIds.length === 0) return 0;
        let records = await selectDataListByParam(TABLENAME.设备数据表, {
            device_id: { "%in%": deviceIds },
            device_time: { "%gte%": formatLocalTime(startTime), "%lte%": formatLocalTime(endTime) },
            "%orderAsc%": "device_time"
        }, ["device_id", "data", "device_time"]);
        
        let total = 0;
        let deviceEnergyMap = new Map();
        for (let rec of records.data) {
            let data = rec.data;
            // let energy = data.energy ?? data.total_energy;
            let energy = data.current;
            if (energy === undefined) continue;
            if (!deviceEnergyMap.has(rec.device_id)) {
                // deviceEnergyMap.set(rec.device_id, { min: energy, max: energy });
                deviceEnergyMap.set(rec.device_id, energy);
            } else {
                let cur = deviceEnergyMap.get(rec.device_id);
                // if (energy < cur.min) cur.min = energy;
                // if (energy > cur.max) cur.max = energy;
                energy += cur;
                deviceEnergyMap.set(rec.device_id, energy);
            }
        }
        for (let energy of deviceEnergyMap.values()) {
            total += energy;
        }
        return total;
    }

    let todayEnergy = await getTotalEnergy(energyDeviceIds, todayStart, todayEnd);
    let yesterdayEnergy = await getTotalEnergy(energyDeviceIds, yesterdayStart, yesterdayEnd);
    let currentMonthEnergy = await getTotalEnergy(energyDeviceIds, currentMonthStart, new Date());
    let previousMonthEnergy = await getTotalEnergy(energyDeviceIds, lastMonthStart, lastMonthEnd);

    let dailyYearOnYear = yesterdayEnergy === 0 ? 0 : (((todayEnergy - yesterdayEnergy) / yesterdayEnergy) * 100).toFixed(2);
    let monthlyYearOnYear = previousMonthEnergy === 0 ? 0 : (((currentMonthEnergy - previousMonthEnergy) / previousMonthEnergy) * 100).toFixed(2);

    // 1.3 用电趋势：过去24小时（按小时）、过去7天、过去30天、过去一年（按月）
    let nowTime = new Date();
    let last24hStart = new Date(nowTime.getTime() - 24 * 3600000);
    let hourlyEnergy = await getEnergyTrend(energyDeviceIds, last24hStart, nowTime, 'hour');
    let last7DaysStart = new Date(nowTime.getTime() - 7 * 86400000);
    let dailyEnergy7 = await getEnergyTrend(energyDeviceIds, last7DaysStart, nowTime, 'day');
    let last30DaysStart = new Date(nowTime.getTime() - 30 * 86400000);
    let dailyEnergy30 = await getEnergyTrend(energyDeviceIds, last30DaysStart, nowTime, 'day');
    let lastYearStart = new Date(nowTime.getFullYear() - 1, nowTime.getMonth(), 1);
    let monthlyEnergyYear = await getEnergyTrend(energyDeviceIds, lastYearStart, nowTime, 'month');

    // 补全 x 轴坐标的工具函数
    function padTrend(trend: any[], allKeys: string[]): any[] {
        const map = new Map(trend.map((item: any) => [item.key, item]));
        return allKeys.map(key => map.get(key) || { key, value: "0" });
    }

    // 过去7天 x 轴补全
    const last7DaysKeys: string[] = [];
    for (let i = 6; i >= 0; i--) {
        const d = new Date(nowTime);
        d.setDate(d.getDate() - i);
        last7DaysKeys.push(`${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}`);
    }
    dailyEnergy7 = padTrend(dailyEnergy7, last7DaysKeys);

    // 过去30天 x 轴补全
    const last30DaysKeys: string[] = [];
    for (let i = 29; i >= 0; i--) {
        const d = new Date(nowTime);
        d.setDate(d.getDate() - i);
        last30DaysKeys.push(`${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}`);
    }
    dailyEnergy30 = padTrend(dailyEnergy30, last30DaysKeys);

    // 过去一年（按月）x 轴补全
    const lastYearKeys: string[] = [];
    for (let i = 11; i >= 0; i--) {
        const d = new Date(nowTime.getFullYear(), nowTime.getMonth() - i, 1);
        lastYearKeys.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`);
    }
    monthlyEnergyYear = padTrend(monthlyEnergyYear, lastYearKeys);

    // 1.4. 能耗监控数据和能耗监控趋势图数据
    resultAny.energyManagement = {
        todayElectricity: todayEnergy.toFixed(0),
        yesterdayElectricity: yesterdayEnergy.toFixed(0),
        dailyYearOnYear,
        currentMonthElectricity: currentMonthEnergy.toFixed(0),
        previousMonthElectricity: previousMonthEnergy.toFixed(0),
        monthlyYearOnYear
    };
    resultAny.electricityTrend = {
        last24HoursMax: Math.max(0, ...hourlyEnergy.map((item: any) => Number(item.value))),
        last24Hours: hourlyEnergy,
        last7DaysMax: Math.max(0, ...dailyEnergy7.map((item: any) => Number(item.value))),
        last7Days: dailyEnergy7,
        last30DaysMax: Math.max(0, ...dailyEnergy30.map((item: any) => Number(item.value))),
        last30Days: dailyEnergy30,
        lastYearMax: Math.max(0, ...monthlyEnergyYear.map((item: any) => Number(item.value))),
        lastYear: monthlyEnergyYear
    };

    // 1.5. 过去24时运行能耗
    let last24hRunningEnergy = hourlyEnergy.reduce((sum: number, item: any) => sum + Number(item.value), 0);


    // 4.1 环境监测九合一
    let airParams: any = {device_type: "环境监测" };
    if (regionGroup) {
        airParams.region_key = { "%in%": regionKeys };
    }
    let airQualityDevices = await selectDataListByParam(TABLENAME.设备表, airParams, ["device_id"]);
    let airDeviceIds = airQualityDevices.data.map(d => d.device_id);
    let qualityIndex = 300;

    // 今日环境质量：{co2:660,hcho:0.01,humidity:70.5,light_level:0,pir:1,pm10:33,pm2_5:31,pressure:1011.7,temperature:21.6,tvoc:1}
    let todayEnvironmental = '优秀';

    let currentCo2 = 0; // 当前二氧化氮
    let co2Trend = [];
    let currentTemperature = '0℃'; // 当前温度
    let temperatureTrend = [];
    let currentHumidity = '0%'; // 当前湿度
    let humidityTrend = [];
    let currentPm25 = 0; // 当前PM2.5
    let pm25Trend = [];
    let co2TrendDetail = [];

    let currentHcho = 0; // 当前甲醛浓度
    let hchoTrend = [];
    let currentLightLevel = 0; // 当前光照强度
    let lightLevelTrend = [];
    let currentPir = ''; // 当前红外感应
    let pirTrend = [];
    let currentPm10 = 0; // 当前PM10
    let pm10Trend = [];
    let currentPressure = 0; // 当前大气压强
    let pressureTrend = [];
    let currentTvoc = 0; // 当前有机物浓度
    let tvocTrend = [];

    if (airDeviceIds.length) {
        // 最新数据
        let latestAir = await selectDataListByParam(TABLENAME.设备数据表, {
            device_id: { "%in%": airDeviceIds },
            "%orderDesc%": "device_time",
            "%limit%": 1
        }, ["data"]);
        if (latestAir.data.length) {
            let airData = latestAir.data[0].data;
            currentTemperature = `${airData.temperature ?? 0}℃`;
            currentHumidity = `${airData.humidity ?? 0}%`;
            currentPm25 = airData.pm2_5??0;
            currentCo2 = airData.co2 ?? 0;
            qualityIndex = 500 - (airData.pm2_5 ?? 0);
            
            currentHcho = airData.hcho??0;
            currentLightLevel = airData.light_level??0;
            currentPm10 = airData.pm10??0;
            currentPressure = airData.pressure??0;
            currentTvoc = airData.tvoc??0;
        }
        // 过去24小时趋势
        let last24h = new Date(nowTime.getTime() - 24*3600000);
        let airHistory = await selectDataListByParam(TABLENAME.设备数据表, {
            device_id: { "%in%": airDeviceIds },
            device_time: { "%gte%": formatLocalTime(last24h) }
        }, ["data", "device_time"]);
        let hourlyData = new Map();
        for (let rec of airHistory.data) {
            let d = new Date(rec.device_time);
            let hourKey = `${d.getHours()}时`;
            let data = rec.data;
            if (!hourlyData.has(hourKey)) {
                hourlyData.set(hourKey, { temp: data.temperature, hum: data.humidity, pm: data.pm2_5, co2: data.co2
                    , hcho: data.hcho, lightLevel: data.light_level, pm10: data.pm10, pressure: data.pressure, tvoc: data.tvoc });
            }
        }
        for (let i = 0; i < 24; i++) {
            let key = `${i}时`;
            let val = hourlyData.get(key);
            temperatureTrend.push({ time: `${i}:00`, value: val?.temp?.toString() ?? '0' });
            humidityTrend.push({ time: `${i}:00`, value: val?.hum?.toString() ?? '0' });
            pm25Trend.push({ time: `${i}:00`, value: val?.pm?.toString() ?? '0' });
            let co2Val = val?.co2 ?? 0;
            co2TrendDetail.push({ time: `${i}:00`, value: (co2Val / 100).toFixed(1) });
            co2Trend.push({ time: `${i}时`, value: co2Val.toString() });

            hchoTrend.push({ time: `${i}:00`, value: val?.hcho?.toString() ?? '0' });
            lightLevelTrend.push({ time: `${i}:00`, value: val?.lightLevel?.toString() ?? '0' });
            pm10Trend.push({ time: `${i}:00`, value: val?.pm10?.toString() ?? '0' });
            pressureTrend.push({ time: `${i}:00`, value: val?.pressure?.toString() ?? '0' });
            tvocTrend.push({ time: `${i}:00`, value: val?.tvoc?.toString() ?? '0' });
        }
    }

    // 计算今日环境质量
    if (currentCo2 && currentPm25) {
        // 优秀：CO2< 800ppm; PM2.5≤35; 甲醛≤0.055
        todayEnvironmental = currentCo2<800 && currentPm25<=35 ? '优秀':
        // 优秀：CO2< 1000ppm; PM2.5≤45; TVOC≤0.4
        currentCo2<1000 && currentPm25<=45 ? '优秀':
        // 良好：CO2≤ 1000ppm; PM2.5≤50; 甲醛≤0.08
        currentCo2<=1000 && currentPm25<=50 ? '良好':
        // 一般：CO2：1000~1500; PM2.5：50~75
        currentCo2>1000 && currentCo2<1500 && currentPm25>50 && currentPm25<75 ? '一般': '差'
    }


    // 4.2. 环境监测趋势图数据
    resultAny.environmentalTrend = {
        todayEnvironmental: todayEnvironmental,
        currentTemperature: currentTemperature,
        currentHumidity: currentHumidity,
        currentPm25: currentPm25+'μg/m³',
        currentCo2: currentCo2+'ppm',
        temperatureTrend: temperatureTrend,
        humidityTrend: humidityTrend,
        pm25Trend: pm25Trend,
        co2Trend: co2Trend,
        qualityIndex: qualityIndex,

        currentHcho: currentHcho,
        currentLightLevel: currentLightLevel,
        currentPm10: currentPm10,
        currentPressure: currentPressure,
        currentTvoc: currentTvoc,
        hchoTrend: hchoTrend,
        lightLevelTrend: lightLevelTrend,
        pm10Trend: pm10Trend,
        pressureTrend: pressureTrend,
        tvocTrend: tvocTrend
    };

    // 5.1 预警监控和预警工单处理进度分析（从 device_fault 表获取，近30天）
    const faultStatusTextMap: { [key: number]: string } = { 0: "未处理", 1: "已响应", 2: "已解决" };

    // 降级默认值：查询或统计失败时使用，保证其他模块不受影响
    let alertStatus = { totalAlerts: 0, resolved: 0, responded: 0, unresolved: 0 };
    let alertWorkLevel: { [key: string]: number } = { "一级预警": 0, "二级预警": 0, "三级预警": 0 };
    let alertWorkType: any[] = [];
    let alertWorkOrders: any[] = [];

    try {
        // 时间范围：近30天
        const thirtyDaysAgo = new Date(nowTime.getTime() - 30 * 86400000);
        const timeFilter = { "%gte%": formatLocalTime(thirtyDaysAgo) };

        // ---- 统计查询：只取 status/level/fault_type，避免传输无用字段 ----
        const statsRes = await selectDataListByParam(TABLENAME.设备故障表,
            { occurred_time: timeFilter },
            ["status", "level", "fault_type"]);
        const statsFaults: any[] = Array.isArray(statsRes.data) ? statsRes.data : [];
        const totalAlerts = statsFaults.length;

        // alertStatus：按处理状态一次遍历统计
        let resolved = 0, responded = 0, unresolved = 0;
        for (const f of statsFaults) {
            if (f.status === 2) resolved++;
            else if (f.status === 1) responded++;
            else if (f.status === 0) unresolved++;
        }
        alertStatus = { totalAlerts, resolved, responded, unresolved };

        // alertWorkLevel：按故障等级统计
        for (const f of statsFaults) {
            if (f.level === 1) alertWorkLevel["一级预警"]++;
            else if (f.level === 2) alertWorkLevel["二级预警"]++;
            else if (f.level === 3) alertWorkLevel["三级预警"]++;
        }

        // alertWorkType：按故障类型统计
        let faultTypeCountMap = new Map<string, number>();
        for (const f of statsFaults) {
            const typeName = f.fault_type || "其他";
            faultTypeCountMap.set(typeName, (faultTypeCountMap.get(typeName) || 0) + 1);
        }
        for (const [name, count] of faultTypeCountMap) {
            alertWorkType.push({
                count,
                name,
                proportion: totalAlerts > 0 ? ((count / totalAlerts) * 100).toFixed(0) + '%' : '0%'
            });
        }

        // ---- 工单列表查询：DB 层倒序 + LIMIT 10，避免全量拉到内存排序 ----
        const ordersRes = await selectDataListByParam(TABLENAME.设备故障表,
            {
                occurred_time: timeFilter,
                "%orderDesc%": "occurred_time",
                "%limit%": 10
            },
            ["id", "device_id", "fault_type", "fault_code", "fault_description", "occurred_time", "level", "status"]);
        const sortedFaults: any[] = Array.isArray(ordersRes.data) ? [...ordersRes.data] : [];

        // 三级页面需要展示 alertAddress，需查设备表和区域表
        let deviceRegionMap = new Map<string, string>();
        if (regionType && sortedFaults.length > 0) {
            const faultUniqueDeviceIds = [...new Set(sortedFaults.map((f: any) => f.device_id))];
            const devicesRes = await selectDataListByParam(TABLENAME.设备表,
                { device_id: { "%in%": faultUniqueDeviceIds } },
                ["device_id", "region_key"]);
            const regionKeySet = new Set<string>();
            const deviceRegionKeyMap = new Map<string, string>();
            for (const d of devicesRes.data) {
                deviceRegionKeyMap.set(d.device_id, d.region_key);
                if (d.region_key) regionKeySet.add(d.region_key);
            }
            if (regionKeySet.size > 0) {
                const regionsRes = await selectDataListByParam(TABLENAME.区域表,
                    { id: { "%in%": [...regionKeySet] }, "%orderAsc%": "sort_order" },
                    ["id", "name"]);
                const regionNameMap = new Map<string, string>();
                for (const r of regionsRes.data) {
                    regionNameMap.set(String(r.id), r.name);
                }
                for (const [deviceId, regionKey] of deviceRegionKeyMap) {
                    deviceRegionMap.set(deviceId, regionNameMap.get(regionKey) || '');
                }
            }

            alertWorkOrders = sortedFaults.map((f: any) => ({
                riskContent: f.fault_description || f.fault_type || '',
                alertTime: f.occurred_time || '',
                status: faultStatusTextMap[f.status] || '未知',
                alertAddress: deviceRegionMap.get(f.device_id) || '',
                device_id: f.device_id || '',
                faultCode: f.fault_code || '',
            }));
        } else {
            alertWorkOrders = sortedFaults.map((f: any) => ({
                riskContent: f.fault_description || f.fault_type || '',
                alertTime: f.occurred_time || '',
                status: faultStatusTextMap[f.status] || '未知',
            }));
        }
    } catch (err) {
        console.error("预警监控数据查询失败，使用空数据降级:", err);
    }

    resultAny.alertManagement = {
        alertStatus,
        alertWorkLevel,
        alertWorkType,
        alertWorkOrders,
    };

    // 6.1 人流监控及客流量趋势分析
    let regionInfos: any = [];
    if (regionKeys.length === 0) {
        // 6.1.1 若没有选择区域，则查询区域表获取所有区域类型
        regionInfos = await selectDataListByParam(TABLENAME.区域表, { "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
    } else {
        // 6.1.2 若选择了区域，则查询选择的区域
        regionInfos = await selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionKeys }, "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
    }
    
    // 6.2 循环区域查询客流传感器设备，获取过去24小时每个区域的客流量
    let totalRegionCustomerNum = 0; // 所有区域的总客流量
    let regionMaxCustomerMap = new Map(); // {regionName: customerMaxNum}
    let regionCustomerMap = new Map(); // {regionName: customerNum}
    let regionCustomerTable = []; // [{regionName: A馆, customerNum: 5000, saturation: '80%'}]
    for (let regionInfo of regionInfos.data) {
        // 区分楼栋与楼层
        let regionName = regionKeys.length === 0 ? regionInfo.groups : regionInfo.type;
        // 如果是按区域类型统计，则最大承载量取该类型下所有区域的总和；如果是按区域名称统计，则取该区域的最大承载量
        let maxCapacity = regionKeys.length === 0 ? regionMaxCustomerMap.get(regionName) : regionInfo.max_capacity;
        regionMaxCustomerMap.set(regionName, maxCapacity); // 区域最大承载量
        // 初始化客流量
        let totalNum = regionCustomerMap.get(regionName) ? regionCustomerMap.get(regionName) : 0;

        let customerDevices = await selectDataListByParam(TABLENAME.设备表, {
            device_type: "客流传感器", region_key: regionInfo.id
        }, ["device_type", "device_id"]);
        let customerDeviceIds = customerDevices.data.map((d: any) => d.device_id);
        // 获取今日的客流量数据
        if (customerDeviceIds && customerDeviceIds.length > 0) {
            let customerDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": customerDeviceIds },
                device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) },
                "%orderAsc%": "device_time"
            }, ["device_id", "data", "device_time"]);

            // 统计区域类型的客流量（新格式使用 in/out）
            for (let rec of customerDeviceDatas.data) {
                let data = rec.data;
                // ====== 旧格式（已弃用，保留备用） ======
                // if (data.current_total) {
                //     totalRegionCustomerNum += data.current_total;
                //     if (!regionCustomerMap.has(regionName)) {
                //         regionCustomerMap.set(regionName, data.current_total);
                //     } else {
                //         regionCustomerMap.set(regionName, totalNum + data.current_total);
                //     }
                // }
                const netVisitor = (data.in ?? 0);
                if (netVisitor > 0) {
                    totalRegionCustomerNum += netVisitor;
                    if (!regionCustomerMap.has(regionName)) {
                        regionCustomerMap.set(regionName, netVisitor);
                    } else {
                        totalNum = regionCustomerMap.get(regionName);
                        regionCustomerMap.set(regionName, totalNum + netVisitor);
                    }
                }
            }
        } else {
            regionCustomerMap.set(regionName, totalNum);
        }
    }
    // 当日客流
    let todayCustomer = 0;
    
    let yesterdayCustomer = 0;
    // 计算每个区域的饱和度（客流量/区域最大承载量），并转换成表格
    for (let [regionName, customerNum] of regionCustomerMap.entries()) {
        let regionMaxCustomer = regionMaxCustomerMap.get(regionName) || 1000; // 默认最大承载量为1000
        let saturation = `${((customerNum / regionMaxCustomer) * 100)>100?100:((customerNum / regionMaxCustomer) * 100).toFixed(2)}%`;
        regionCustomerTable.push({ regionName, customerNum, saturation });
        todayCustomer += customerNum;
    }
    
    // 6.3 客流量趋势分析：根据查询到的客流传感器数据，统计所选区域过去24小时客流量变化趋势
    let customerTrend = [];
    let customerParams: any = { device_type: "客流传感器" };
    if (regionGroup) {
        customerParams.region_key = { "%in%": regionKeys };
    }
    let customerDevices = await selectDataListByParam(TABLENAME.设备表, customerParams, ["device_type", "device_id"]);
    if (customerDevices.data.length > 0) {
        let customerDeviceIds = customerDevices.data.map((d: any) => d.device_id);
        // 获取过去24小时客流量数据
        let customerDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
            device_id: { "%in%": customerDeviceIds },
            device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) },
            "%orderAsc%": "device_time"
        }, ["device_id", "data", "device_time"]);
        let hourlyCustomerMap = new Map();
        for (let rec of customerDeviceDatas.data) {
            let d = new Date(rec.device_time);
            let hourKey = `${d.getHours()}时`;
            let data = rec.data;
            // ====== 旧格式（已弃用，保留备用） ======
            // let customerNum = data.current_total;
            // ====== 新格式使用 in ======
            let customerNum = data.in ?? 0;
            if (!hourlyCustomerMap.has(hourKey)) {
                hourlyCustomerMap.set(hourKey, customerNum);
            } else {
                let totalNum = hourlyCustomerMap.get(hourKey);
                hourlyCustomerMap.set(hourKey, totalNum + customerNum);
            }
        }
        // 填充过去24小时的客流量趋势数据
        for (let i = 0; i < 24; i++) {
            let key = `${i}时`;
            let val = hourlyCustomerMap.get(key) ?? 0;
            customerTrend.push({ time: `${i}:00`, value: val });
        }

        // 获取昨日客流量数据
        let yesterdayDatas = await selectDataListByParam(TABLENAME.设备数据表, {
            device_id: { "%in%": customerDeviceIds },
            device_time: { "%gte%": formatLocalTime(yesterdayStart), "%lte%": formatLocalTime(yesterdayEnd) },
            "%orderAsc%": "device_time"
        }, ["device_id", "data", "device_time"]);
        for (let rec of yesterdayDatas.data) {
            let data = rec.data;
            // ====== 旧格式（已弃用，保留备用） ======
            // let customerNum = data.current_total;
            // ====== 新格式使用 in ======
            let customerNum = data.in ?? 0;
            yesterdayCustomer += customerNum;
        }
    }
    // 6.4. 人流监控实时数据和趋势图数据
    resultAny.customerOnlineTrend = {
        todayCustomer: todayCustomer,
        customerCompare: (todayCustomer - yesterdayCustomer) / yesterdayCustomer * 100, // 同比昨日(今日人流量-昨日人流量)÷昨日人流量x100%
        passengerFlowTable: regionCustomerTable,
        customerTrend: customerTrend
    };

    // 三级页面不需要执行此逻辑
    if (!regionType) {
        // 2.1 获取所选区域空调设备运行状态数据（如空调数、在线率、故障率等）
        let acParams: any = { device_type: "空调" };
        if (regionGroup) {
            acParams.region_key = { "%in%": regionKeys };
        }
        let acDevices = await selectDataListByParam(TABLENAME.设备表, acParams, ["device_id", "device_state"]);
        let acDeviceIds = acDevices.data.map((d: any) => d.device_id);

        let acCount = acDeviceIds.length;
        let acOfflineCount = acDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length;
        let acOnlineCount = acCount - acOfflineCount;
        let acFaultRecords = await selectDataListByParam(
            TABLENAME.设备故障表,
            { status: { "%ne%": 2 }, device_id: { "%in%": acDeviceIds } },
            ["device_id"]
        );
        let acFaultDeviceIds = new Set(acFaultRecords.data.map((r: any) => r.device_id));
        let acFaultDevices = acFaultDeviceIds.size;
        let acNormalRate = acCount === 0 ? '100%' : (((acCount - acFaultDevices) / acCount) * 100).toFixed(2) + '%';
        let acFaultCount = acFaultRecords.data.length; //所有未解决的故障单数量（含同一设备多个故障）
        // 2.2 获取今日空调在线趋势分析数据
        let acOnlineTrend = [];
        if (acDeviceIds.length) {
            // 2.2.1 获取过去24小时设备数据
            let last24h = new Date(nowTime.getTime() - 24 * 3600000);
            let acHistory = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": acDeviceIds },
                device_time: { "%gte%": formatLocalTime(last24h) }
            }, ["device_id", "data", "device_time"]);
            // 2.2.2 按小时统计在线设备数和总设备数
            let hourlyData = new Map();
            for (let rec of acHistory.data) {
                let d = new Date(rec.device_time);
                let hourKey = `${d.getHours()}时`;
                let data = rec.data;
                console.log(data);
                if (!hourlyData.has(hourKey)) {
                    let totalNum = 1;
                    let onlineNum = data.power === "on" ? 1 : 0;
                    hourlyData.set(hourKey, { online: onlineNum, total: totalNum });
                } else {
                    let totalNum = hourlyData.get(hourKey).total;
                    let onlineNum = hourlyData.get(hourKey).online;
                    if (data.power === "on") onlineNum += 1;
                    hourlyData.set(hourKey, { online: onlineNum, total: totalNum + 1 });
                }
            }
            console.log("空调在线数据（过去24小时）:", hourlyData);
            // 2.2.3 填充24小时空调在线数据，没有在线数据的小时段则设为零，并计算每小时的空调在线率
            for (let i = 0; i < 24; i++) {
                let key = `${i}时`;
                let val = hourlyData.get(key);
                acOnlineTrend.push({ time: `${i}:00`, value: val ? ((val.online / val.total) * 100).toFixed(2) : '0' });
            }


        }
        // 2.4. 空调设备在线趋势图数据
        resultAny.acDeviceOnlineTrend = {
            acCount: acDeviceIds.length,
            acOnlineCount: acOnlineCount,
            acOfflineCount: acOfflineCount,
            acFaultCount: acFaultCount,
            acOnlineTrend: acOnlineTrend
        };

        // 3.1 新风运行监控
        let fanParams: any = { device_type: "新风" };
        if (regionGroup) {
            fanParams.region_key = { "%in%": regionKeys };
        }
        let fanDevices = await selectDataListByParam(TABLENAME.设备表, fanParams, ["device_id", "device_state"]);
        let fanDeviceIds = fanDevices.data.map((d: any) => d.device_id);

        let fanCount = fanDeviceIds.length;
        let fanOfflineCount = fanDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length;
        let fanOnlineCount = fanCount - fanOfflineCount;
        let fanFaultRecords = await selectDataListByParam(
            TABLENAME.设备故障表,
            { status: { "%ne%": 2 }, device_id: { "%in%": fanDeviceIds } },
            ["device_id"]
        );
        let fanFaultDeviceIds = new Set(fanFaultRecords.data.map((r: any) => r.device_id));
        let fanFaultDevices = fanFaultDeviceIds.size;
        let fanNormalRate = fanCount === 0 ? '100%' : (((fanCount - fanFaultDevices) / fanCount) * 100).toFixed(2) + '%';
        let fanFaultCount = fanFaultRecords.data.length; //所有未解决的故障单数量（含同一设备多个故障）

        // 3.2 新风风量运行监测趋势分析数据（如果有风量数据）
        let fanOnlineTrend = [];
        if (fanDeviceIds.length) {
            let fanDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": fanDeviceIds },
                device_time: { "%gte%": formatLocalTime(last24hStart), "%lte%": formatLocalTime(nowTime) },
                "%orderAsc%": "device_time"
            }, ["device_id", "data", "device_time"]);
            // 3.2.1 按小时统计新风送风量（换气次数=送风量/房间体积）
            let hourlyData = new Map(); // {key: 00:00, ly: 0, ry: 0 }
            for (let rec of fanDeviceDatas.data) {
                let d = new Date(rec.device_time);
                let hourKey = `${d.getHours()}时`;
                let data = rec.data;
                if (!hourlyData.has(hourKey)) {
                    hourlyData.set(hourKey, { airSupply: airSupplyKeyMap[data.fanSpeed] });
                }
            }
            // 3.2.2 填充24小时新风监控数据，没有在线数据的小时段则设为零，并计算每小时的新风送风量
            for (let i = 0; i < 24; i++) {
                let key = `${i}时`;
                let val = hourlyData.get(key);
                fanOnlineTrend.push({ time: `${i}:00`, value: val ? val.airSupply : '0' });
            }
        }
        // 3.3. 新风设备在线趋势图数据
        resultAny.fanDeviceOnlineTrend = {
            fanCount: fanDeviceIds.length,
            fanOnlineCount: fanOnlineCount,
            fanOfflineCount: fanOfflineCount,
            fanFaultCount: fanFaultCount,
            fanOnlineTrend: fanOnlineTrend
        };

        // 7.1 获取区域列表接口，供前端下拉选择区域类型和区域名称
        let regionMap: any = await getRegionList(regionGroup);
        // 7.2. 区域列表数据
        resultAny.regionData = regionMap;

        // 运行监控总数据（一天）
        resultAny.mainRunningManagement = {
            totalCustomerNumber: totalRegionCustomerNum,
            totalDeviceOnlineRate: (acOnlineCount/acCount*100)>=100?'100':(acOnlineCount/acCount*100).toFixed(1),
            // totalElectricity: last24hRunningEnergy.toFixed(0).slice(0, 5),
            totalElectricity: last24hRunningEnergy.toFixed(0),
        };
    } else {
        // 设备监控总数据
        let devices = await selectDataListByParam(TABLENAME.设备表, {
            region_key: { "%in%": regionKeys }
        }, ["device_id", "device_state"]);
        let deviceIds = devices.data.map((d: any) => d.device_id);

        let deviceCount = deviceIds.length;
        let deviceOfflineCount = devices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length;
        let deviceOnlineCount = deviceCount - deviceOfflineCount;
        let deviceFaultRecords = await selectDataListByParam(
            TABLENAME.设备故障表,
            { status: { "%ne%": 2 }, device_id: { "%in%": deviceIds } },
            ["device_id"]
        );
        let deviceFaultDeviceIds = new Set(deviceFaultRecords.data.map((r: any) => r.device_id));
        let deviceFaultDevices = deviceFaultDeviceIds.size;
        let deviceNormalRate = deviceCount === 0 ? '100%' : (((deviceCount - deviceFaultDevices) / deviceCount) * 100).toFixed(2) + '%';
        let deviceFaultCount = deviceFaultRecords.data.length; //所有未解决的故障单数量（含同一设备多个故障）
        resultAny.mainRunningManagement = {
            deviceCount: deviceIds.length,
            deviceOnlineCount: deviceOnlineCount,
            deviceOfflineCount: deviceOfflineCount,
            deviceFaultCount: deviceFaultCount,
        };
    }

    // 最终组装返回数据
    // let resultAny: any = {
    //     // 区域列表数据
    //     regionData: regionMap,
    //     // 运行监控总数据（一天）
    //     mainRunningManagement: {
    //         totalCustomerNumber: 10000,
    //         totalDeviceOnlineRate: '99.8%',
    //         totalElectricity: `360kwh`,
    //     },
    //     // 能耗监控数据
    //     energyManagement: {
    //         todayElectricity: `${todayEnergy.toFixed(0)}kwh`,
    //         yesterdayElectricity: `${yesterdayEnergy.toFixed(0)}kwh`,
    //         dailyYearOnYear,
    //         currentMonthElectricity: `${currentMonthEnergy.toFixed(0)}kwh`,
    //         previousMonthElectricity: `${previousMonthEnergy.toFixed(0)}kwh`,
    //         monthlyYearOnYear
    //     },
    //     // 能耗监控趋势图数据
    //     electricityTrend: {
    //         last24Hours: hourlyEnergy,
    //         last7Days: dailyEnergy7,
    //         last30Days: dailyEnergy30,
    //         lastYear: monthlyEnergyYear
    //     },
    //     // 空调设备在线趋势图数据
    //     acDeviceOnlineTrend: {
    //         acCount: acDeviceIds.length,
    //         acOnlineCount: acOnlineCount,
    //         acOfflineCount: acOfflineCount,
    //         acFaultCount: acFaultCount,
    //         acOnlineTrend: acOnlineTrend
    //     },
    //     // 新风设备在线趋势图数据
    //     fanDeviceOnlineTrend: {
    //         fanCount: fanDeviceIds.length,
    //         fanOnlineCount: fanOnlineCount,
    //         fanOfflineCount: fanOfflineCount,
    //         fanFaultCount: fanFaultCount,
    //         fanOnlineTrend: fanOnlineTrend
    //     },
    //     // 环境监测趋势图数据
    //     environmentalTrend: {
    //         currentTemperature: currentTemperature,
    //         currentHumidity: currentHumidity,
    //         currentPm25: currentPm25,
    //         currentCo2: currentCo2,
    //         temperatureTrend: temperatureTrend,
    //         humidityTrend: humidityTrend,
    //         pm25Trend: pm25Trend,
    //         co2Trend: co2Trend,
    //         qualityIndex: qualityIndex
    //     },
    //     // 人流监控实时数据和趋势图数据
    //     customerOnlineTrend: {
    //         passengerFlowTable: regionCustomerTable,
    //         customerTrend: customerTrend
    //     },
    //     // 预警监控数据
    //     alertManagement: {
    //         alertWorkLevel: alertWorkLevel,
    //         alertWorkType: alertWorkType,
    //         alertWorkOrders: alertWorkOrders
    //     }
    // };
    return resultAny;
}

/**
 * 智能管控-空调设备运行弹窗
 * @param regionKey 
 * @param deviceId 
 */
export async function getAcRunningPop(regionKey: number, deviceId: string) {
    // 获取设备信息
    let devices = await selectDataListByParam(
        TABLENAME.设备表,
        { region_key: regionKey, device_id: deviceId },
        ["device_id", "device_type", "device_name", "control_params"]
    );
    if (!devices.data.length) {
        throw new BizError(ERRORENUM.未找到数据, `设备 ${deviceId} 在区域 ${regionKey} 中未找到`);
    }
    // 获取设备最新数据
    let deviceData = await selectDataListByParam(
        TABLENAME.设备数据表,
        { device_id: deviceId, "%orderDesc%": "device_time", "%limit%": 1 },
        ["data", "device_time"]
    );
    return {
        deviceInfo: devices.data[0].control_params,
        latestData: deviceData.data.length ? deviceData.data[0].data : null
    }
}

/**
 * 设备运行弹框 - 空调启停
 * @param deviceId 
 */
export async function controlAcRunning(params: {}) {
    let deviceId = params["deviceId"];
    let mode = params["mode"];
    let power = params["power"];
    let setTemp = params["setTemp"];
    let maxTemp = params["maxTemp"] || 28;  // 默认锁定温度上限
    let minTemp = params["minTemp"] || 16;  // 默认锁定温度下限
    let autoControl = params["autoControl"];
    let fanSpeed = params["fanSpeed"];

    // 1. 通过设备信息，获取内机地址
    let device = await selectOneDataByParam(
        TABLENAME.设备表,
        { device_id: deviceId },
        ["id", "device_id", "region_key", "device_name", "device_ad", "control_params"]
    );
    if (!device.data || !device.data.id) {
        throw new BizError(ERRORENUM.未找到数据, `设备 ${deviceId} 未注册`);
    }
    // 2. 接入空调控制API，更新空调设备信息
    let acPrarms = { 
        "indoorUnitAddressFull": [deviceId], 
        "workMode": acDeviceKeyMap[mode], 
        "onOff": acDeviceKeyMap[power], 
        "tempSet": Number(setTemp), 
        "fanSpeed": acDeviceKeyMap[fanSpeed], 
        "onOffLock": acDeviceKeyMap[autoControl], 
        "workModeLock": acDeviceKeyMap[autoControl], 
        "tempSetLock": acDeviceKeyMap[autoControl], 
        "tempSetLo": Number(minTemp), 
        "tempSetHi": Number(maxTemp), 
        "openApiAction": autoControl === "生效" ? "control" : "lock"
    };
    return await controlIndoorUnit(acPrarms);
}

// 辅助函数：获取用电趋势（按间隔分组）
async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Date, granularity: 'hour' | 'day' | 'month') {
    if (deviceIds.length === 0) return [];
    let records = await selectDataListByParam(TABLENAME.设备数据表, {
        device_id: { "%in%": deviceIds },
        device_time: { "%gte%": formatLocalTime(startTime), "%lte%": formatLocalTime(endTime) },
        "%orderAsc%": "device_time"
    }, ["device_id", "data", "device_time"]);
    
    let intervalMap = new Map(); // key: 时间字符串, value: { deviceMin, deviceMax }
    for (let rec of records.data) {
        let data = rec.data;
        // let energy = data.energy ?? data.total_energy;
        let energy = data.current;
        if (energy === undefined) continue;
        let intervalKey: string;
        let d = new Date(rec.device_time);
        const pad = (n: number) => String(n).padStart(2, '0');
        if (granularity === 'hour') {
            intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}时`;
        } else if (granularity === 'day') {
            intervalKey = `${d.getFullYear()}/${pad(d.getMonth()+1)}/${pad(d.getDate())}`;
        } else {
            intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}`;
        }
        if (!intervalMap.has(intervalKey)) {
            intervalMap.set(intervalKey, energy);
        } else {
            energy = intervalMap.get(intervalKey) + energy;
            intervalMap.set(intervalKey, energy);
        }
    }
    let result = [];
    for (let [key, energy] of intervalMap.entries()) {
        result.push({ key, value: energy.toFixed(0) });
    }
    result.sort((a, b) => a.key.localeCompare(b.key));
    return result;
}

// 判断当前季节：5-9月为夏季（制冷），其余为冬季（制热）
function getSeason(): 'summer' | 'winter' {
    const month = new Date().getMonth() + 1;
    return (month >= 5 && month <= 9) ? 'summer' : 'winter';
}

// 根据IAQ温度计算空调设定温度
/**
 * 根据文档 Slide 39 三段式温度段，计算联动控制参数
 * 返回：目标温度、风速、开关状态
 */
function calcAcTempSet(temperature: number, season: 'summer' | 'winter'): { tempSet: number; fanSpeed: number; onOff: number } {
    if (season === 'summer') {
        // 夏季制冷：温度越高，设定越低
        if (temperature > 26) return { tempSet: 22, fanSpeed: 1, onOff: 1 };   // 未达需求：高风制冷
        if (temperature >= 22) return { tempSet: 24, fanSpeed: 4, onOff: Math.round(temperature) === 24 ? 0 : 1 };  // 舒适区：四舍五入24℃待机
        return { tempSet: 26, fanSpeed: 4, onOff: 1 };                          // 已达需求：低风维持
    } else {
        // 冬季制热：温度越低，设定越高
        if (temperature < 18) return { tempSet: 21, fanSpeed: 1, onOff: 1 };   // 未达需求：高风制热
        if (temperature <= 21) return { tempSet: 20, fanSpeed: 4, onOff: Math.round(temperature) === 20 ? 0 : 1 };  // 舒适区：四舍五入20℃待机
        return { tempSet: 18, fanSpeed: 4, onOff: 1 };                          // 已达需求：低风维持
    }
}

// 根据IAQ CO2浓度计算新风控制参数
function calcFanParams(co2: number): { action: 'high' | 'low' | 'standby' } | null {
    if (co2 > 1000) return { action: 'high' };   // 新风开启，风量调高
    if (co2 < 800) return { action: 'low' };      // 风量调低，新风待机
    return null; // 800-1000 区间不做调整
}

// 基于馆内环境温度、CO2浓度等，联动空调启停及新风控制
export async function controlAcByEnvironment(deviceId: string, data: any) {
    // 获取区域内环境监测设备数据
    let envDevices = await selectDataListByParam(TABLENAME.设备表, {
        device_id: deviceId,
        device_type: "环境监测"
    }, ["id", "device_name", "region_key"]);

    const now = new Date();
    const operationTime = now.toISOString().replace('T', ' ').slice(0, 19);
    const season = getSeason();
    const temperature = data.temperature;
    const co2 = data.co2;

    // 若是环境设备，则解析环境设备数据，判断是否需要联动
    if (envDevices.data.length) {
        let regionKey = envDevices.data[0].region_key;

        // ===== 空调联动 =====
        if (temperature != null) {
            let acDevices = await selectDataListByParam(TABLENAME.设备表, {
                region_key: regionKey,
                device_type: "空调"
            }, ["id", "device_name", "device_id", "device_ad", "control_params"]);

            if (acDevices.data.length > 0) {
                const { tempSet, fanSpeed, onOff } = calcAcTempSet(temperature, season);
                const workMode = season === 'summer' ? 1 : 2; // 1制冷 2制热
                const modeName = season === 'summer' ? '制冷' : '制热';

                // 取空调设备数据信息中的温度上下限
                let maxTemp: number | undefined;
                let minTemp: number | undefined;
                const acDeviceIds = acDevices.data.map((d: any) => d.device_id);
                if (acDeviceIds.length) {
                    const acDataRes = await selectDataListByParam(TABLENAME.设备数据表, {
                        device_id: { "%in%": acDeviceIds },
                        "%orderDesc%": "device_time",
                        "%limit%": 1
                    }, ["data"]);
                    if (acDataRes.data.length) {
                        const acData = acDataRes.data[0].data;
                        maxTemp = acData.maxTemp || 28;
                        minTemp = acData.minTemp || 16;
                    }
                }

                // 去重：若本次计算的控制参数与上次相同，跳过调用
                const cacheKey = `ac_${regionKey}`;
                const lastState = envControlCache.get(cacheKey);
                if (lastState && lastState.tempSet === tempSet && lastState.workMode === workMode && lastState.fanSpeed === fanSpeed && lastState.onOff === onOff && lastState.maxTemp === maxTemp && lastState.minTemp === minTemp) {
                    console.log(`空调联动跳过(控制参数未变): ${modeName}模式, 设定${tempSet}℃, 风速${fanSpeed === 1 ? '高' : '低'}风, ${onOff ? '开机' : '待机'}, 区域 ${regionKey}`);
                } else {
                    let controlRes = await controlAcRunningApi(acDevices, workMode, tempSet, fanSpeed, onOff, maxTemp, minTemp);

                    // 更新缓存
                    envControlCache.set(cacheKey, { tempSet, workMode, fanSpeed, onOff, maxTemp, minTemp });

                    // 空调日志
                    const acLogs = acDevices.data.map((ac: any) => ({
                        device_id: ac.device_id,
                        device_type: '空调',
                        operation_content: {
                            option: '自动联动控制',
                            device_id: deviceId,
                            time: operationTime,
                            season,
                            mode: modeName,
                            roomTemp: temperature,
                            setTemp: tempSet,
                            success: controlRes.success,
                            message: controlRes.message || (controlRes.success ? '控制成功' : '控制失败'),
                        },
                        status: controlRes.success ? 1 : 0,
                        created_at: now,
                        updated_at: now,
                    }));
                    await addData(TABLENAME.设备日志表, acLogs);

                    if (controlRes.success) {
                        console.log(`空调联动(${modeName})成功: IAQ温度${temperature}℃ → 设定${tempSet}℃, 设备 ${deviceId}`);
                    } else {
                        console.error(`空调联动(${modeName})失败: ${controlRes.message}`);
                    }
                }
            }
        }

        // ===== 新风联动(后执行，通过送风模式覆盖空调温控) =====
        if (co2 != null) {
            const fanParams = calcFanParams(co2);
            if (fanParams) {
                let fanDevices = await selectDataListByParam(TABLENAME.设备表, {
                    region_key: regionKey,
                    device_type: { "%in%": ["新风", "空调"] }
                }, ["id", "device_name", "device_id", "device_ad", "device_type"]);

                if (fanDevices.data.length > 0) {
                    // CO2联动：高→送风模式(3)+高风(1)，低→不传workMode(不切换模式)+低风(4)
                    const fanWorkMode: number | undefined = fanParams.action === 'high' ? 3 : undefined;
                    const fanSpeedVal = fanParams.action === 'high' ? 1 : 4;

                    // 去重
                    const fanCacheKey = `fan_${regionKey}`;
                    const lastFanState = envControlCache.get(fanCacheKey);
                    if (lastFanState && lastFanState.co2Action === fanParams.action && lastFanState.workMode === fanWorkMode && lastFanState.fanSpeed === fanSpeedVal) {
                        console.log(`新风联动跳过(参数未变): CO2 ${co2}ppm, ${fanParams.action === 'high' ? '送风高风' : '低风待机'}, 区域 ${regionKey}`);
                    } else {
                        let fanControlRes = await controlAcRunningApi(fanDevices, fanWorkMode, undefined, fanSpeedVal, 1);

                        // 更新缓存（含 workMode/fanSpeed 用于去重）
                        envControlCache.set(fanCacheKey, { co2Action: fanParams.action, workMode: fanWorkMode, fanSpeed: fanSpeedVal });

                        const fanLogs = fanDevices.data.map((fan: any) => ({
                            device_id: fan.device_id,
                            device_type: fan.device_type || '新风',
                            operation_content: {
                                option: '自动联动控制',
                                device_id: deviceId,
                                time: operationTime,
                                roomCo2: co2,
                                mode: fanParams.action === 'high' ? '送风' : '低风待机',
                                action: fanParams.action === 'high' ? '送风高风' : '低风不切换模式',
                                success: fanControlRes.success,
                                message: fanControlRes.message || (fanControlRes.success ? '控制成功' : '控制失败'),
                            },
                            status: fanControlRes.success ? 1 : 0,
                            created_at: now,
                            updated_at: now,
                        }));
                        await addData(TABLENAME.设备日志表, fanLogs);

                        if (fanControlRes.success) {
                            console.log(`新风联动成功: CO2 ${co2}ppm → ${fanParams.action === 'high' ? '送风高风' : '低风待机'}, 设备 ${deviceId}`);
                        } else {
                            console.error(`新风联动失败: ${fanControlRes.message}`);
                        }
                    }
                }
            }
        }
    }
}

// 辅助：接入空调控制API，根据温度设定值启停空调设备
async function controlAcRunningApi(acDevices?: any, workMode?: number, tempSet?: number, fanSpeed?: number, onOff?: number, maxTemp?: number, minTemp?: number) {
    let deviceList: any = [];
    acDevices.data.forEach((ac: any) => {
        deviceList.push(ac.device_id);
    });

    let controlResults: any = { "success": false, "message": "失败" };
    if (deviceList.length === 0) return controlResults;

    let params: any = {
        "indoorUnitAddressFull": deviceList,
        "onOff": onOff ?? 1,  // 联动时按温差动态判断，默认开机兜底
        "fanSpeed": fanSpeed ?? 2,  // 联动时按温差动态计算，默认中风兜底
        "openApiAction": "control",
    };
    // workMode 为 undefined 时不传，飞奕不切换模式
    if (workMode != null) {
        params.workMode = workMode;
    }
    // 如果传入了设定温度，一并下发
    if (tempSet != null) {
        params.tempSet = tempSet;
    }
    // 下发温度锁定上下限（取自设备数据信息）
    if (maxTemp != null) {
        params.tempSetHi = maxTemp;
    }
    if (minTemp != null) {
        params.tempSetLo = minTemp;
    }

    let res = await controlIndoorUnit(params);
    if (res.success) {
        controlResults.success = true;
        controlResults.devices = deviceList;
        controlResults.message = '控制成功';
    } else {
        controlResults.success = false;
        controlResults.devices = deviceList;
        controlResults.message = res.data || '控制空调设备失败';
    }
    return controlResults;
}

/**
 * 设置开关机
 * @param regionGroup 
 * @param regionFloor 
 * @param regionKey 
 * @param deviceId 
 * @param powerStatus 
 */
export async function scheduledPowerOn(regionGroup:string, regionType:string, regionKey:number, deviceId:string, powerStatus:number) {
    // 根据regionGroup\regionType\regionKey查询区域信息
    // 根据deviceId查询空调设备
    // 无传参时，查询region表，通过region表查询device表中device_type=空调的数据
    // 循环查询的空调设备，组装空调控制需要参数
    // 调用空调控制的第三方接口并记录device_log日志表
}

/**
 * 数据集成 - 启动定时任务
 */
export async function startScheduleTask() {
    await startSchedule();
    return { success: true };
}
/**
 * 数据集成 - 停止定时任务
 */
export async function stopScheduleTask() {
    await stopSchedule();
    return { success: true };
}

/**
 * 空调中文到Key的映射
 * 1 制冷 2 制热 3 送风 4 除湿
 * 0 关-off 1 开-on
 * 1 高风-超强 2 中风-强 4 低风-弱
 * 0 不锁定-生效 1 锁定-解除
 */
let acDeviceKeyMap: { [key: string]: number } = {
    "制冷": 1,
    "制热": 2,
    "送风": 3,
    "除湿": 4,
    "on": 1,
    "off": 0,
    "超强": 1,
    "强": 2,
    "弱": 4,
    "解除": 1,
    "生效": 0
}

/**
 * 区域楼层到Key的映射
 */
let regionTypeKeyMap: { [key: string]: string } = {
    "1F": "一层",
    "2F": "一层",
    "3F": "一层"
}

/**
 * 风速等级到送风量的映射
 */
let airSupplyKeyMap: { [key: string]: number } = {
    "自动": 900,
    "弱": 876,
    "强": 1068,
    "超强": 1272
}







