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 时区偏移问题
 */
export 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);

    // 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);
    // === 前提：公共时间变量，后续并行模块都会用到 ===
    let nowTime = new Date();
    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);
    // 昨日同时段结束时间（日同比窗口）
    let yesterdaySameTimeEnd = new Date(yesterdayStart);
    yesterdaySameTimeEnd.setHours(nowTime.getHours(), nowTime.getMinutes(), nowTime.getSeconds(), nowTime.getMilliseconds());
    // 上月同比截止日（处理月份天数差异）
    let todayDay = nowTime.getDate();
    let thisMonthMaxDay = new Date(nowTime.getFullYear(), nowTime.getMonth() + 1, 0).getDate();
    let lastMonthMaxDay = new Date(nowTime.getFullYear(), nowTime.getMonth(), 0).getDate();
    let comparisonDay = todayDay;
    if (todayDay == thisMonthMaxDay && thisMonthMaxDay < lastMonthMaxDay) {
        comparisonDay = lastMonthMaxDay;
    } else {
        comparisonDay = Math.min(todayDay, lastMonthMaxDay);
    }
    let lastMonthComparisonEnd = new Date(nowTime.getFullYear(), nowTime.getMonth() - 1, comparisonDay,
        nowTime.getHours(), nowTime.getMinutes(), nowTime.getSeconds(), nowTime.getMilliseconds());
    let last24hStart = new Date(nowTime.getTime() - 24 * 3600000);
    let last7DaysStart = new Date(nowTime.getTime() - 7 * 86400000);
    let last30DaysStart = new Date(nowTime.getTime() - 30 * 86400000);
    let lastYearStart = new Date(nowTime.getFullYear() - 1, nowTime.getMonth(), 1);

    // === 并行执行：能耗、环境、预警、客流 四个独立模块 ===
    const parallelResults = await Promise.all([
        // 模块1：能耗管理
        (async () => {
            // 一次查询覆盖所有时间范围
            let allEnergyRecords = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": energyDeviceIds },
                device_time: { "%gte%": formatLocalTime(lastYearStart), "%lte%": formatLocalTime(nowTime) },
                "%orderAsc%": "device_time"
            }, ["device_id", "data", "device_time"]);

            // 一次遍历，同时产出：4个时段总量 + 4组趋势数据
            let todayTotal = 0, yesterdayTotal = 0, yesterdayWindowTotal = 0, currentMonthTotal = 0, previousMonthTotal = 0, previousMonthWindowTotal = 0;
            let deviceTodayMap = new Map<string, number>();
            let deviceYesterdayMap = new Map<string, number>();
            let deviceYesterdayWindowMap = new Map<string, number>();
            let deviceMonthMap = new Map<string, number>();
            let devicePrevMonthMap = new Map<string, number>();
            let devicePrevMonthWindowMap = new Map<string, number>();
            let hourlyMap = new Map<string, number>();
            let daily7Map = new Map<string, number>();
            let daily30Map = new Map<string, number>();
            let monthlyMap = new Map<string, number>();

            const padFn = (n: number) => String(n).padStart(2, '0');

            for (let rec of allEnergyRecords.data) {
                let energy = rec.data?.current;
                if (energy === undefined) continue;
                let d = new Date(rec.device_time);
                let ts = d.getTime();
                let deviceId = rec.device_id;

                // --- 总量分组 ---
                if (ts >= todayStart.getTime()) {
                    deviceTodayMap.set(deviceId, (deviceTodayMap.get(deviceId) || 0) + energy);
                }
                if (ts >= yesterdayStart.getTime() && ts <= yesterdayEnd.getTime()) {
                    deviceYesterdayMap.set(deviceId, (deviceYesterdayMap.get(deviceId) || 0) + energy);
                }
                if (ts >= yesterdayStart.getTime() && ts <= yesterdaySameTimeEnd.getTime()) {
                    deviceYesterdayWindowMap.set(deviceId, (deviceYesterdayWindowMap.get(deviceId) || 0) + energy);
                }
                if (ts >= currentMonthStart.getTime()) {
                    deviceMonthMap.set(deviceId, (deviceMonthMap.get(deviceId) || 0) + energy);
                }
                if (ts >= lastMonthStart.getTime() && ts <= lastMonthEnd.getTime()) {
                    devicePrevMonthMap.set(deviceId, (devicePrevMonthMap.get(deviceId) || 0) + energy);
                }
                if (ts >= lastMonthStart.getTime() && ts <= lastMonthComparisonEnd.getTime()) {
                    devicePrevMonthWindowMap.set(deviceId, (devicePrevMonthWindowMap.get(deviceId) || 0) + energy);
                }

                // --- 趋势分组 ---
                if (ts >= last24hStart.getTime()) {
                    let key = `${d.getFullYear()}-${padFn(d.getMonth()+1)}-${padFn(d.getDate())} ${padFn(d.getHours())}时`;
                    hourlyMap.set(key, (hourlyMap.get(key) || 0) + energy);
                }
                if (ts >= last7DaysStart.getTime()) {
                    let key = `${d.getFullYear()}/${padFn(d.getMonth()+1)}/${padFn(d.getDate())}`;
                    daily7Map.set(key, (daily7Map.get(key) || 0) + energy);
                }
                if (ts >= last30DaysStart.getTime()) {
                    let key = `${d.getFullYear()}/${padFn(d.getMonth()+1)}/${padFn(d.getDate())}`;
                    daily30Map.set(key, (daily30Map.get(key) || 0) + energy);
                }
                let monthKey = `${d.getFullYear()}-${padFn(d.getMonth()+1)}`;
                monthlyMap.set(monthKey, (monthlyMap.get(monthKey) || 0) + energy);
            }

            // 汇总各时段总量
            for (let v of deviceTodayMap.values()) todayTotal += v;
            for (let v of deviceYesterdayMap.values()) yesterdayTotal += v;
            for (let v of deviceYesterdayWindowMap.values()) yesterdayWindowTotal += v;
            for (let v of deviceMonthMap.values()) currentMonthTotal += v;
            for (let v of devicePrevMonthMap.values()) previousMonthTotal += v;
            for (let v of devicePrevMonthWindowMap.values()) previousMonthWindowTotal += v;

            // map 转为排序后的数组
            let hourlyEnergy: { key: string, value: string }[] = [];
            hourlyMap.forEach((v, k) => hourlyEnergy.push({ key: k, value: v.toFixed(0) }));
            hourlyEnergy.sort((a, b) => a.key.localeCompare(b.key));

            let dailyEnergy7: { key: string, value: string }[] = [];
            daily7Map.forEach((v, k) => dailyEnergy7.push({ key: k, value: v.toFixed(0) }));
            dailyEnergy7.sort((a, b) => a.key.localeCompare(b.key));

            let dailyEnergy30: { key: string, value: string }[] = [];
            daily30Map.forEach((v, k) => dailyEnergy30.push({ key: k, value: v.toFixed(0) }));
            dailyEnergy30.sort((a, b) => a.key.localeCompare(b.key));

            let monthlyEnergyYear: { key: string, value: string }[] = [];
            monthlyMap.forEach((v, k) => monthlyEnergyYear.push({ key: k, value: v.toFixed(0) }));
            monthlyEnergyYear.sort((a, b) => a.key.localeCompare(b.key));

            let dailyYearOnYear = yesterdayWindowTotal === 0 ? 0 : (((todayTotal - yesterdayWindowTotal) / yesterdayWindowTotal) * 100).toFixed(2);
            let monthlyYearOnYear = previousMonthWindowTotal === 0 ? 0 : (((currentMonthTotal - previousMonthWindowTotal) / previousMonthWindowTotal) * 100).toFixed(2);

            // 补全 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: todayTotal.toFixed(0),
                yesterdayElectricity: yesterdayWindowTotal.toFixed(0),
                yesterdayTotalElectricity: yesterdayTotal.toFixed(0),
                dailyYearOnYear,
                currentMonthElectricity: currentMonthTotal.toFixed(0),
                previousMonthElectricity: previousMonthWindowTotal.toFixed(0),
                previousMonthTotalElectricity: previousMonthTotal.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时运行能耗
            return { last24hRunningEnergy: hourlyEnergy.reduce((sum: number, item: any) => sum + Number(item.value), 0) };
        })(),

        // 模块2：环境监测
        (async () => {
            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;

            let todayEnvironmental = '优秀';

            let currentCo2 = 0;
            let co2Trend = [];
            let currentTemperature = '0℃';
            let temperatureTrend = [];
            let currentHumidity = '0%';
            let humidityTrend = [];
            let currentPm25 = 0;
            let pm25Trend = [];
            let co2TrendDetail = [];

            let currentHcho = 0;
            let hchoTrend = [];
            let currentLightLevel = 0;
            let lightLevelTrend = [];
            let currentPir = '';
            let pirTrend = [];
            let currentPm10 = 0;
            let pm10Trend = [];
            let currentPressure = 0;
            let pressureTrend = [];
            let currentTvoc = 0;
            let tvocTrend = [];

            if (airDeviceIds.length) {
                // 并行查询每个环境监测设备的最新一条数据（拆分 IN+ORDER BY 为 N 个精准索引查询）
                let latestResults = await Promise.all(
                    airDeviceIds.map((deviceId: string) =>
                        selectDataListByParam(TABLENAME.设备数据表, {
                            device_id: deviceId,
                            "%orderDesc%": "device_time",
                            "%limit%": 1
                        }, ["data", "device_time"])
                    )
                );
                // 找出时间最新的一条记录
                let latestAir: any = null;
                for (let res of latestResults) {
                    if (res.data.length > 0) {
                        if (!latestAir || new Date(res.data[0].device_time) > new Date(latestAir.data[0].device_time)) {
                            latestAir = res;
                        }
                    }
                }
                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;
                }
                let todayStartEnv = new Date(nowTime);
                todayStartEnv.setHours(0, 0, 0, 0);
                let airHistory = await selectDataListByParam(TABLENAME.设备数据表, {
                    device_id: { "%in%": airDeviceIds },
                    device_time: { "%gte%": formatLocalTime(todayStartEnv), "%lte%": formatLocalTime(nowTime) }
                }, ["data", "device_time"]);
                let hourlyData = new Map();
                const fieldMap: Record<string, string> = { temp: 'temperature', hum: 'humidity', pm: 'pm2_5', co2: 'co2', hcho: 'hcho', lightLevel: 'light_level', pm10: 'pm10', pressure: 'pressure', tvoc: 'tvoc' };
                for (let rec of airHistory.data) {
                    let d = new Date(rec.device_time);
                    let hourKey = `${d.getHours()}时`;
                    let data = rec.data;
                    let cur = hourlyData.get(hourKey);
                    if (!cur) {
                        cur = { cnt: 0 };
                        hourlyData.set(hourKey, cur);
                    }
                    cur.cnt++;
                    for (let field of ['temp', 'hum', 'pm', 'co2', 'hcho', 'lightLevel', 'pm10', 'pressure', 'tvoc']) {
                        let key = field + 'Sum';
                        cur[key] = (cur[key] || 0) + (Number(data[fieldMap[field]]) || 0);
                    }
                }
                const currentHour = nowTime.getHours();
                for (let i = 0; i < 24; i++) {
                    let key = `${i}时`;
                    let val = hourlyData.get(key);
                    let avg = (sumKey: string) => val?.cnt ? ((val[sumKey] || 0) / val.cnt).toFixed(1) : '0';
                    if (i <= currentHour) {
                        temperatureTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('tempSum') : '0' });
                        humidityTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('humSum') : '0' });
                        pm25Trend.push({ time: `${i}:00`, value: val?.cnt ? avg('pmSum') : '0' });
                        let co2Val = val?.cnt ? ((val['co2Sum'] || 0) / val.cnt) : 0;
                        co2TrendDetail.push({ time: `${i}:00`, value: (co2Val / 100).toFixed(1) });
                        co2Trend.push({ time: `${i}时`, value: co2Val.toFixed(0) });
                        
                        hchoTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('hchoSum') : '0' });
                        lightLevelTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('lightLevelSum') : '0' });
                        pm10Trend.push({ time: `${i}:00`, value: val?.cnt ? avg('pm10Sum') : '0' });
                        pressureTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('pressureSum') : '0' });
                        tvocTrend.push({ time: `${i}:00`, value: val?.cnt ? avg('tvocSum') : '0' });
                    } else {
                        temperatureTrend.push({ time: `${i}:00`, value: '0' });
                        humidityTrend.push({ time: `${i}:00`, value: '0' });
                        pm25Trend.push({ time: `${i}:00`, value: '0' });
                        co2TrendDetail.push({ time: `${i}:00`, value: '0' });
                        co2Trend.push({ time: `${i}时`, value: '0' });

                        hchoTrend.push({ time: `${i}:00`, value: '0' });
                        lightLevelTrend.push({ time: `${i}:00`, value: '0' });
                        pm10Trend.push({ time: `${i}:00`, value: '0' });
                        pressureTrend.push({ time: `${i}:00`, value: '0' });
                        tvocTrend.push({ time: `${i}:00`, value: '0' });
                    }
                }
            }

            if (currentCo2 && currentPm25) {
                todayEnvironmental = currentCo2<800 && currentPm25<=35 ? '优秀':
                currentCo2<1000 && currentPm25<=45 ? '优秀':
                currentCo2<=1000 && currentPm25<=50 ? '良好':
                currentCo2>1000 && currentCo2<1500 && currentPm25>50 && currentPm25<75 ? '一般': '差'
            }

            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
            };
        })(),

        // 模块3：预警监控
        (async () => {
            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 {
                const todayFilter = { "%gte%": formatLocalTime(todayStart) };
                const thirtyDaysAgo = new Date(nowTime.getTime() - 30 * 86400000);
                const thirtyDayFilter = { "%gte%": formatLocalTime(thirtyDaysAgo) };

                // alertWorkLevel：查今日三个级别的预警数量
                const levelRes = await selectDataListByParam(TABLENAME.设备故障表,
                    { occurred_time: todayFilter },
                    ["level"]);
                const levelFaults: any[] = Array.isArray(levelRes.data) ? levelRes.data : [];
                for (const f of levelFaults) {
                    if (f.level === 1) alertWorkLevel["一级预警"]++;
                    else if (f.level === 2) alertWorkLevel["二级预警"]++;
                    else if (f.level === 3) alertWorkLevel["三级预警"]++;
                }

                // alertWorkType：查今日各故障类型占比
                const todayTypeRes = await selectDataListByParam(TABLENAME.设备故障表,
                    { occurred_time: todayFilter },
                    ["fault_type"]);
                const todayTypeFaults: any[] = Array.isArray(todayTypeRes.data) ? todayTypeRes.data : [];
                const todayAlertTotal = todayTypeFaults.length;
                let faultTypeCountMap = new Map<string, number>();
                for (const f of todayTypeFaults) {
                    const typeName = f.fault_type || "其他";
                    faultTypeCountMap.set(typeName, (faultTypeCountMap.get(typeName) || 0) + 1);
                }
                for (const [name, count] of faultTypeCountMap) {
                    alertWorkType.push({
                        count,
                        name,
                        proportion: todayAlertTotal > 0 ? ((count / todayAlertTotal) * 100).toFixed(0) + '%' : '0%'
                    });
                }

                // alertStatus：查近 30 天不同状态的预警
                const statsRes = await selectDataListByParam(TABLENAME.设备故障表,
                    { occurred_time: thirtyDayFilter },
                    ["status"]);
                const statsFaults: any[] = Array.isArray(statsRes.data) ? statsRes.data : [];
                const totalAlerts = statsFaults.length;

                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 };

                // alertWorkOrders：查近 30 天未处理的预警列表
                const ordersRes = await selectDataListByParam(TABLENAME.设备故障表,
                    {
                        occurred_time: thirtyDayFilter,
                        status: 0,
                        "%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] : [];

                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);
                    }
                    let deviceOrderAddressMap = new Map<string, string>();
                    if (regionKeySet.size > 0) {
                        const regionsRes = await selectDataListByParam(TABLENAME.区域表,
                            { id: { "%in%": [...regionKeySet] }, "%orderAsc%": "sort_order" },
                            ["id", "name", "groups", "type"]);
                        const regionNameMap = new Map<string, string>();
                        for (const r of regionsRes.data) {
                            regionNameMap.set(String(r.id), r.name);
                            deviceOrderAddressMap.set(String(r.id), `${r.groups || ''}_${r.type || ''}`);
                        }
                        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 || '',
                        order_address: deviceOrderAddressMap.get(deviceRegionKeyMap.get(f.device_id)?.toString()) || '',
                        order_send: 'on', // TODO: 后续需要实现工单推送的实际逻辑
                    }));
                // } else {
                //     alertWorkOrders = sortedFaults.map((f: any) => ({
                //         riskContent: f.fault_description || f.fault_type || '',
                //         alertTime: f.occurred_time || '',
                //         status: faultStatusTextMap[f.status] || '未知',
                //         order_address: '',
                //         order_send: 'on', // TODO: 后续需要实现工单推送的实际逻辑
                //     }));
                // }
            } catch (err) {
                console.error("预警监控数据查询失败，使用空数据降级:", err);
            }

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

        // 模块4：客流监控（批量查询优化：N 次 per-region 查询 → 3 次 DB 查询）
        (async () => {
            let regionInfos: any = [];
            if (regionKeys.length === 0) {
                regionInfos = await selectDataListByParam(TABLENAME.区域表, { "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
            } else {
                regionInfos = await selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionKeys }, "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
            }

            const allRegionIds = regionInfos.data.map((r: any) => r.id);

            // 建立 regionKey -> 显示名称 / maxCapacity 映射
            const regionKeyToName = new Map<string, string>();
            const regionMaxCustomerMap = new Map<string, number>();
            for (let r of regionInfos.data) {
                let name = regionKeys.length === 0 ? r.groups : r.type;
                regionKeyToName.set(r.id, name);
                let maxCap = regionKeys.length === 0 ? regionMaxCustomerMap.get(name) : r.max_capacity;
                regionMaxCustomerMap.set(name, maxCap);
            }

            // 1. 批量查询所有客流传感器设备（1 次 DB 查询替代 N 次）
            let allCustomerDevices = await selectDataListByParam(TABLENAME.设备表, {
                device_type: "客流传感器",
                region_key: { "%in%": allRegionIds }
            }, ["device_type", "device_id", "region_key"]);

            const deviceRegionMap = new Map<string, string>();
            const allCustomerDeviceIds: string[] = [];
            for (let d of allCustomerDevices.data) {
                allCustomerDeviceIds.push(d.device_id);
                deviceRegionMap.set(d.device_id, d.region_key);
            }

            let regionCustomerMap = new Map<string, number>();
            let totalRegionCustomerNum = 0;
            let todayCustomer = 0;
            let yesterdayCustomer = 0;
            let customerTrend: { time: string; value: number }[] = [];
            let regionCustomerTable: any[] = [];

            if (allCustomerDeviceIds.length > 0) {
                // 2. 批量查询今日设备数据（合并 per-region 统计 + 趋势图，1 次 DB 查询）
                let todayDatas = await selectDataListByParam(TABLENAME.设备数据表, {
                    device_id: { "%in%": allCustomerDeviceIds },
                    device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) },
                    "%orderAsc%": "device_time"
                }, ["device_id", "data", "device_time"]);

                // 3. 批量查询昨日设备数据（1 次 DB 查询）
                let yesterdayDatas = await selectDataListByParam(TABLENAME.设备数据表, {
                    device_id: { "%in%": allCustomerDeviceIds },
                    device_time: { "%gte%": formatLocalTime(yesterdayStart), "%lte%": formatLocalTime(yesterdayEnd) },
                    "%orderAsc%": "device_time"
                }, ["device_id", "data", "device_time"]);

                // 一次遍历今日数据：按区域统计 + 按小时聚合趋势
                let hourlyCustomerMap = new Map<string, number>();
                for (let rec of todayDatas.data) {
                    let data = rec.data;
                    let netVisitor = data.in ?? 0;
                    // 区域统计（只统计 >0 的值）
                    if (netVisitor > 0) {
                        totalRegionCustomerNum += netVisitor;
                        let rk = deviceRegionMap.get(rec.device_id) || '';
                        let regionName = regionKeyToName.get(rk) || rk;
                        regionCustomerMap.set(regionName, (regionCustomerMap.get(regionName) || 0) + netVisitor);
                    }
                    // 趋势聚合（所有值，含 0）
                    let d = new Date(rec.device_time);
                    let hourKey = `${d.getHours()}时`;
                    hourlyCustomerMap.set(hourKey, (hourlyCustomerMap.get(hourKey) || 0) + netVisitor);
                }

                // 昨日汇总
                for (let rec of yesterdayDatas.data) {
                    yesterdayCustomer += (rec.data?.in ?? 0);
                }

                // 补全无传感器区域为 0
                for (let r of regionInfos.data) {
                    let name = regionKeyToName.get(r.id) || '';
                    if (!regionCustomerMap.has(name)) {
                        regionCustomerMap.set(name, 0);
                    }
                }

                // 构建区域饱和度表格
                for (let [regionName, customerNum] of regionCustomerMap.entries()) {
                    let maxCap = regionMaxCustomerMap.get(regionName) || 1000;
                    let saturation = `${Math.min(((customerNum / maxCap) * 100), 100).toFixed(2)}%`;
                    regionCustomerTable.push({ regionName, customerNum, saturation });
                    todayCustomer += customerNum;
                }

                // 构建24小时趋势
                for (let i = 0; i < 24; i++) {
                    customerTrend.push({ time: `${i}:00`, value: hourlyCustomerMap.get(`${i}时`) ?? 0 });
                }
            } else {
                // 无客流传感器，所有区域填 0
                for (let r of regionInfos.data) {
                    let name = regionKeyToName.get(r.id) || '';
                    regionCustomerMap.set(name, 0);
                    regionCustomerTable.push({ regionName: name, customerNum: 0, saturation: '0%' });
                }
            }

            resultAny.customerOnlineTrend = {
                todayCustomer: todayCustomer,
                customerCompare: yesterdayCustomer > 0 ? ((todayCustomer - yesterdayCustomer) / yesterdayCustomer * 100) : 0,
                passengerFlowTable: regionCustomerTable,
                customerTrend: customerTrend
            };

            return { todayCustomer, yesterdayCustomer, totalRegionCustomerNum };
        })(),
    ]);

    const energyResult = parallelResults[0] as { last24hRunningEnergy: number };
    const customerResult = parallelResults[3] as { totalRegionCustomerNum: number };
    const last24hRunningEnergy = energyResult.last24hRunningEnergy;
    const totalRegionCustomerNum = customerResult.totalRegionCustomerNum;

    // 三级页面不需要执行此逻辑
    if (!regionType) {
        // AC + Fan + RegionList 彼此独立，并行执行
        let [acResult, fanResult, regionMap] = await Promise.all([
            // 2. 空调设备运行监控
            (async () => {
                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 acFaultCount = acFaultRecords.data.length;

                let acOnlineTrend: { time: string; value: string }[] = [];
                if (acDeviceIds.length) {
                    let acHistory = await selectDataListByParam(TABLENAME.设备数据表, {
                        device_id: { "%in%": acDeviceIds },
                        device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(nowTime) }
                    }, ["device_id", "data", "device_time"]);
                    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;
                        if (!hourlyData.has(hourKey)) {
                            hourlyData.set(hourKey, { online: data.power === "on" ? 1 : 0, total: 1 });
                        } else {
                            let v = hourlyData.get(hourKey);
                            if (data.power === "on") v.online += 1;
                            v.total += 1;
                            hourlyData.set(hourKey, v);
                        }
                    }
                    let currentHour = nowTime.getHours();
                    for (let i = 0; i < 24; i++) {
                        if (i <= currentHour) {
                            let key = `${i}时`;
                            let val = hourlyData.get(key);
                            acOnlineTrend.push({ time: `${i}:00`, value: val ? ((val.online / val.total) * 100).toFixed(2) : '0' });
                        } else {
                            acOnlineTrend.push({ time: `${i}:00`, value: '0' });
                        }
                    }
                }
                return { acDeviceIds, acCount, acOnlineCount, acOfflineCount, acFaultCount, acOnlineTrend };
            })(),
            // 3. 新风运行监控
            (async () => {
                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 fanFaultCount = fanFaultRecords.data.length;

                let fanOnlineTrend: { time: string; value: string }[] = [];
                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"]);
                    let hourlyData = new Map();
                    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] });
                        }
                    }
                    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' });
                    }
                }
                return { fanDeviceIds, fanCount, fanOnlineCount, fanOfflineCount, fanFaultCount, fanOnlineTrend };
            })(),
            // 7. 区域列表
            getRegionList(regionGroup)
        ]);

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

        // 3.3. 新风设备在线趋势图数据
        resultAny.fanDeviceOnlineTrend = {
            fanCount: fanResult.fanCount,
            fanOnlineCount: fanResult.fanOnlineCount,
            fanOfflineCount: fanResult.fanOfflineCount,
            fanFaultCount: fanResult.fanFaultCount,
            fanOnlineTrend: fanResult.fanOnlineTrend
        };

        // 7.2. 区域列表数据
        resultAny.regionData = regionMap;

        // 运行监控总数据（一天）
        resultAny.mainRunningManagement = {
            totalCustomerNumber: totalRegionCustomerNum,
            totalDeviceOnlineRate: (acResult.acOnlineCount / acResult.acCount * 100) >= 100 ? '100' : (acResult.acOnlineCount / acResult.acCount * 100).toFixed(1),
            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.设备表,
        { device_id: deviceId }, // region_key: regionKey,
        ["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"]
    );
    
    let detailData = deviceData.data.length ? deviceData.data[0].data : null;
    detailData.fanSpeed = detailData && detailData.fanSpeed ? acDeviceKeyMap[detailData.fanSpeed] : 2;

    return {
        deviceInfo: devices.data[0].control_params,
        latestData: detailData
    }
}

/**
 * 设备运行弹框 - 空调启停
 * @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": mode ? acDeviceKeyMap[mode] : 1, // 关机时传一个默认模式
        // "onOff": acDeviceKeyMap[power], 
        "onOff": 1, // TODO：临时处理，等待前端调好就改回通过传参处理
        "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"
        "openApiAction": "control" // TODO：临时处理
    };
    const result = await controlIndoorUnit(acPrarms);
    // 手动控制日志
    const now = new Date();
    const operationTime = new Date();
    const operationTimeStr = formatLocalTime(operationTime);
    const acLogs = [{
        device_id: deviceId,
        device_type: '空调',
        operation_content: {
            option: '手动控制',
            device_id: deviceId,
            time: operationTimeStr,
            mode: mode,
            power: power,
            setTemp: setTemp,
            fanSpeed: fanSpeed,
            autoControl: autoControl,
            maxTemp: maxTemp,
            minTemp: minTemp,
            success: result.success,
            message: result.message || (result.success ? '控制成功' : '控制失败'),
        },
        status: result.success ? 1 : 0,
        created_at: now,
        updated_at: now,
    }];
    await addData(TABLENAME.设备日志表, acLogs);
    return result;
}

/**
 * 获取本月累计用电（按天）
 * 查询三相电表/电能监测设备的每日用电量，补全当月 1 日到今天的 x 轴
 * @param regionGroup 区域分组
 */
export async function getCurrentMonthDailyEnergy(regionGroup: string) {
    // 1. 查区域
    let regionParam: any = {};
    if (regionGroup) {
        regionParam.region_group = regionGroup;
    }
    let regionInfo: any = await selectDataListByParam(TABLENAME.区域表, regionParam, ["id"]);
    let regionKeys = regionInfo.data.map((r: any) => r.id);

    // 2. 查三相电表/电能监测设备
    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);
    if (energyDeviceIds.length === 0) return [];

    // 3. 时间范围：本月 1 日 ~ 现在
    const now = new Date();
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0);

    // 4. 查设备数据
    let records = await selectDataListByParam(TABLENAME.设备数据表, {
        device_id: { "%in%": energyDeviceIds },
        device_time: { "%gte%": formatLocalTime(monthStart), "%lte%": formatLocalTime(now) },
        "%orderAsc%": "device_time"
    }, ["device_id", "data", "device_time"]);

    // 5. 按天聚合用电量
    const dayMap = new Map<string, number>();
    for (let rec of records.data) {
        let energy = rec.data?.current;
        if (energy === undefined) continue;
        let d = new Date(rec.device_time);
        const pad = (n: number) => String(n).padStart(2, '0');
        const key = `${d.getFullYear()}/${pad(d.getMonth() + 1)}/${pad(d.getDate())}`;
        dayMap.set(key, (dayMap.get(key) || 0) + energy);
    }

    // 6. 补全本月 1 日到今天的每一天（缺失填 0）
    const result: { key: string; value: string }[] = [];
    const todayDate = now.getDate();
    for (let i = 1; i <= todayDate; i++) {
        const d = new Date(now.getFullYear(), now.getMonth(), i);
        const pad = (n: number) => String(n).padStart(2, '0');
        const key = `${d.getFullYear()}/${pad(d.getMonth() + 1)}/${pad(d.getDate())}`;
        result.push({ key, value: String(dayMap.get(key) || 0) });
    }
    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 > 24) return { tempSet: 16, fanSpeed: 1, onOff: 1 };   // 未达需求：高风制冷
        if (temperature >= 21) return { tempSet: 18, fanSpeed: 1, onOff: 1};  // 舒适区：四舍五入21℃待机 Math.round(temperature) === 21 ? 0 : 1 
        return { tempSet: 19, fanSpeed: 1, onOff: 1 };                          // 已达需求：低风维持
    } else {
        // 冬季制热：温度越低，设定越高
        if (temperature < 18) return { tempSet: 21, fanSpeed: 1, onOff: 1 };   // 未达需求：高风制热
        if (temperature <= 21) return { tempSet: 20, fanSpeed: 1, onOff: 1};  // 舒适区：四舍五入20℃待机 Math.round(temperature) === 20 ? 0 : 1 
        return { tempSet: 18, fanSpeed: 1, 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, regionName:string) {
    // 获取区域内环境监测设备数据
    let envDevices = await selectDataListByParam(TABLENAME.设备表, {
        device_id: deviceId,
        device_type: "环境监测"
    }, ["id", "device_name", "region_key"]);

    const now = new Date();
    const operationTime = formatLocalTime(now);
    const season = getSeason();
    const temperature = data.temperature;
    const co2 = data.co2;
    console.log(`若是环境设备，则解析环境设备数据，判断是否需要联动 ${envDevices.data.length}`);
    // 若是环境设备，则解析环境设备数据，判断是否需要联动
    if (envDevices.data.length) {
        let regionKey = envDevices.data[0].region_key;

        // ===== 新风联动(后执行，通过送风模式覆盖空调温控) =====
        if (co2 != null && !regionName?.includes("原料厅") 
            && !regionName?.includes("社会责任厅") 
            && !regionName?.includes("中途酒吧")) {
            const fanParams = calcFanParams(co2);
            if (fanParams) {
                let fanDevices = await selectDataListByParam(TABLENAME.设备表, {
                    region_key: regionKey,
                    device_type: { "%in%": ["新风", "空调"] },
                    linkage_start: 'on'
                }, ["id", "device_name", "device_id", "device_ad", "device_type"]);
console.log(`若是新风设备，判断联动是否开启 ${fanDevices.data.length}`);
                if (fanDevices.data.length > 0) {
                    // CO2联动：高→送风模式(3)+高风(1)，低→不传workMode(不切换模式)+低风(4)
                    // const fanWorkMode: number | undefined = fanParams.action === 'high' ? 3 : undefined;
                    const fanWorkMode = 1;
                    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 });

                        let temp = calcAcTempSet(temperature, season);

                        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 ? '控制成功' : '控制失败'),
                                setTemp: temp?.tempSet,
                            },
                            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}`);
                        }
                    }
                }
            }
        }
console.log(`若是空调设备，判断温度是否为空 ${temperature}`);
        // ===== 空调联动 =====
        if (temperature != null) {
            let acDevices = await selectDataListByParam(TABLENAME.设备表, {
                region_key: regionKey,
                device_type: "空调",
                linkage_start: 'on'
            }, ["id", "device_name", "device_id", "device_ad", "control_params"]);
console.log(`若是空调设备，判断联动是否开启 ${acDevices.data.length}`);
            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}`);
                    }
                // }
            }
        }
    }
}

// 辅助：接入空调控制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;
    } else {
        params.workMode = 1; // 设置默认为制冷模式
    }
    // 如果传入了设定温度，一并下发
    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 锁定-解除
 */
export let acDeviceKeyMap: { [key: string]: number } = {
    "制冷": 1,
    "制热": 2,
    "送风": 3,
    "除湿": 4,
    "on": 1,
    "off": 0,
    "超强": 1,
    "强": 2,
    "弱": 4,
    "解除": 1,
    "生效": 0,
    "高风": 1,
    "中风": 2,
    "低风": 4,
    "开": 1,
    "关": 0
}

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

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







