/**
 * 周报告模块
 * - 查询最近七天各馆（A/B/C馆）的设备监测数据
 * - 提供周报告 JSON 数据接口
 */

import { TABLENAME } from "../config/dbEnum";
import { selectDataListByParam } from "../data/findData";

// ======================= 常量 =======================

const HALL_NAMES = ["A馆", "B馆", "C馆"];
const HALL_KEYS = ["total_a", "total_b", "total_c"];
const TABLE_TITLE_LIST = ["时间", "运行时长", "温度℃", "客流量", "总耗电量"];

// ======================= 工具函数 =======================

/** 格式化日期为 'YYYY-MM-DD HH:mm:ss' */
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())}`;
}

/** 并行查询三馆区域，按 groups 分组 */
async function queryHallRegions(): Promise<Map<string, number[]>> {
    const results = await Promise.all(
        HALL_NAMES.map(g => selectDataListByParam(TABLENAME.区域表, { groups: g, "%orderAsc%": "sort_order" }, ["id"]))
    );
    const hallRegionMap = new Map<string, number[]>();
    for (let i = 0; i < HALL_NAMES.length; i++) {
        const ids = (results[i].data || []).map((r: any) => r.id);
        if (ids.length > 0) hallRegionMap.set(HALL_NAMES[i], ids);
    }
    return hallRegionMap;
}

// ======================= JSON 数据接口 =======================

/** 格式化日期为中文 "YYYY年M月D日" */
function formatChineseDate(date: Date): string {
    return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
}

/** 格式化日期为 "YYYY-MM-DD" */
function formatDateStr(date: Date): string {
    const pad = (n: number) => String(n).padStart(2, '0');
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
}

/** 计算最近七天的起止时间（今天往前推6天） */
function calcWeekRange(weekOffset: number = 0): { start: Date; end: Date; timer: string } {
    const now = new Date();
    const end = new Date(now);
    end.setDate(now.getDate() + weekOffset * 7);
    end.setHours(23, 59, 59, 999);
    const start = new Date(now);
    start.setDate(now.getDate() - 6 + weekOffset * 7);
    start.setHours(0, 0, 0, 0);

    const timer = `${formatChineseDate(start)} — ${formatChineseDate(end)}`;
    return { start, end, timer };
}

/** 格式化数字，不足时返回 "——" */
function fmtNum(val: number | null): string {
    if (val == null) return "——";
    return String(Math.round(val * 10) / 10);
}

/** 格式化能耗，保留两位小数，为 0 时返回 "——" */
function fmtEnergy(val: number): string {
    if (val <= 0) return "——";
    return String(Math.round(val * 100) / 100) + "kwh";
}

/** 按周七天生成日期数组 */
function genWeekDays(monday: Date): Date[] {
    return Array.from({ length: 7 }, (_, i) => {
        const d = new Date(monday);
        d.setDate(monday.getDate() + i);
        return d;
    });
}

/** 获取某天 00:00 ~ 23:59 的时间字符串 */
function dayRange(day: Date): { from: string; to: string } {
    const start = new Date(day);
    start.setHours(0, 0, 0, 0);
    const end = new Date(day);
    end.setHours(23, 59, 59, 999);
    return { from: formatLocalTime(start), to: formatLocalTime(end) };
}

/** 某馆的所有设备分组（用于批量查询） */
interface HallDeviceGroup {
    acDevices: { device_id: string; device_name: string; region_name: string; region_key: number }[];
    envDevices: { device_id: string; device_name: string; region_key: number }[];
    customerDevices: { device_id: string; device_name: string; region_key: number }[];
    meterDevices: { device_id: string; device_name: string; region_key: number }[];
    allDeviceIds: string[];
    allDevices: { device_id: string; device_name: string; device_type: string; region_key: number }[];
}

/**
 * 查询某馆下所有类型设备并分组
 */
async function queryHallDeviceGroup(regionIds: number[]): Promise<HallDeviceGroup> {
    if (regionIds.length === 0) {
        return { acDevices: [], envDevices: [], customerDevices: [], meterDevices: [], allDeviceIds: [], allDevices: [] };
    }

    // 并行查询该馆设备和区域名称
    const [allDevRes, regionRes] = await Promise.all([
        selectDataListByParam(TABLENAME.设备表, { region_key: { "%in%": regionIds } }, ["device_id", "device_name", "device_type", "region_key"]),
        selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionIds }, "%orderAsc%": "sort_order" }, ["id", "name"]),
    ]);

    const nameMap = new Map<number, string>();
    for (const r of (regionRes.data || [])) {
        nameMap.set(r.id, r.name || "");
    }

    const allDevices = (allDevRes.data || []).map((d: any) => ({
        device_id: d.device_id,
        device_name: d.device_name || d.device_id,
        device_type: d.device_type,
        region_key: d.region_key,
    }));

    const acDevices = allDevices
        .filter(d => d.device_type === "空调" || d.device_type === "新风")
        .map(d => ({ ...d, region_name: nameMap.get(d.region_key) || "" }));

    return {
        acDevices,
        envDevices: allDevices.filter(d => d.device_type === "环境监测"),
        customerDevices: allDevices.filter(d => d.device_type === "客流传感器"),
        meterDevices: allDevices.filter(d => d.device_type === "电能监测"),
        allDeviceIds: allDevices.map(d => d.device_id),
        allDevices,
    };
}

/**
 * 从空调/新风设备数据中计算运行时长
 */
function calcAcRunHours(records: any[], dayEndTime: Date): number {
    const sorted = records.slice().sort(
        (a, b) => new Date(a.device_time).getTime() - new Date(b.device_time).getTime(),
    );
    let runHours = 0;
    for (let i = 0; i < sorted.length; i++) {
        const d = sorted[i].data || {};
        if (d.power === "on") {
            const t1 = new Date(sorted[i].device_time).getTime();
            const t2 = i + 1 < sorted.length
                ? new Date(sorted[i + 1].device_time).getTime()
                : dayEndTime.getTime();
            if (t2 > t1) runHours += (t2 - t1) / (1000 * 60 * 60);
        }
    }
    return runHours;
}

/**
 * 从环境监测设备数据中计算室温均值（使用 data.temperature 字段）
 */
function calcEnvDeviceDaily(records: any[]): { tempSum: number; tempCount: number } {
    let tempSum = 0, tempCount = 0;
    for (const rec of records) {
        const d = rec.data || {};
        if (d.temperature != null && Number(d.temperature) !== 0) {
            tempSum += Number(d.temperature);
            tempCount++;
        }
    }
    return { tempSum, tempCount };
}

/**
 * 从客流传感器数据中计算当日平均在馆人数
 * 新格式使用 data.in（进）和 data.out（出）
 * // 旧格式（已弃用，保留备用）：current_total 为当时在场人数（瞬时值），取当日所有采集值的算术平均
 */
function calcCustomerDeviceDaily(records: any[]): { visitorSum: number; visitorCount: number } {
    let sum = 0, count = 0;
    for (const rec of records) {
        const d = rec.data || {};
        // ====== 新格式使用 in ======
        if (d.in != null) {
            sum += Number(d.in);
            count++;
        }
        // ====== 旧格式（已弃用，保留备用） ======
        // if (d.current_total != null) {
        //     sum += Number(d.current_total);
        //     count++;
        // }
    }
    return { visitorSum: sum, visitorCount: count };
}

/**
 * 从电表数据中计算24时总用电量（累加每次上报的 current 值）
 */
function calcMeterDeviceDaily(records: any[]): number {
    let total = 0;
    for (const rec of records) {
        const d = rec.data || {};
        if (d.current != null) {
            total += Number(d.current);
        }
    }
    return total;
}

/**
 * 查询周报告 JSON 数据（最近七天）
 * @param weekOffset 0=最近七天(默认), -1=再往前七天, ...
 */
export async function getWeeklyReportData(weekOffset: number = 0): Promise<any> {
    const { start: monday, end: sunday, timer } = calcWeekRange(weekOffset);
    console.log(`[周报告JSON] 查询数据: ${timer}`);

    // ===== 第一步：并行查询区域 + 各馆设备分组 =====
    const hallRegionMap = await queryHallRegions();
    const weekDays = genWeekDays(monday);

    const groups = await Promise.all(
        HALL_NAMES.map(h => queryHallDeviceGroup(hallRegionMap.get(h) || []))
    );
    const hallDeviceGroups = new Map<string, HallDeviceGroup>();
    for (let i = 0; i < HALL_NAMES.length; i++) {
        hallDeviceGroups.set(HALL_NAMES[i], groups[i]);
        console.log(`[周报告JSON] ${HALL_NAMES[i]}: AC${groups[i].acDevices.length} 环境${groups[i].envDevices.length} 客流${groups[i].customerDevices.length} 电表${groups[i].meterDevices.length}`);
    }

    // ===== 预查询：一次性拉取所有设备未解决故障 =====
    const allDeviceIdsUnion = groups.reduce<string[]>((arr, g) => arr.concat(g.allDeviceIds), []);
    const faultSet = new Set<string>();
    if (allDeviceIdsUnion.length > 0) {
        const faultRes = await selectDataListByParam(TABLENAME.设备故障表, {
            device_id: { "%in%": allDeviceIdsUnion },
            status: { "%ne%": 2 },
            occurred_time: { "%lte%": formatLocalTime(sunday) },
        }, ["device_id"]);
        for (const f of (faultRes.data || [])) faultSet.add(f.device_id);
    }

    // ===== 第二步：逐馆逐天查询 + 聚合汇总 =====
    const runDatas: any = {};
    const dataTotal: any = {};
    let overallEnergy = 0, overallVisitor = 0, overallTempSum = 0, overallTempCount = 0;

    for (let idx = 0; idx < HALL_NAMES.length; idx++) {
        const hallName = HALL_NAMES[idx];
        const hallKey = HALL_KEYS[idx];
        const group = hallDeviceGroups.get(hallName)!;
        const tableList: string[][] = [];

        let hallTotalEnergy = 0, hallTotalVisitor = 0;
        let hallTempSum = 0, hallTempCount = 0, hallTotalRunHours = 0;

        for (const day of weekDays) {
            if (group.allDeviceIds.length === 0) break;

            const { from, to } = dayRange(day);
            const dayEnd = new Date(day);
            dayEnd.setHours(23, 59, 59, 999);

            const dayDataRes = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": group.allDeviceIds },
                device_time: { "%gte%": from, "%lte%": to },
                "%orderAsc%": "device_time",
            }, ["device_id", "data", "device_time"]);

            // 按设备 ID 分组
            const deviceDataMap = new Map<string, any[]>();
            for (const rec of (dayDataRes.data || [])) {
                const did = rec.device_id;
                if (!deviceDataMap.has(did)) deviceDataMap.set(did, []);
                deviceDataMap.get(did)!.push(rec);
            }

            let dayRunHours = 0, dayTempSum = 0, dayTempCount = 0;
            let dayEnergy = 0, dayVisitorSum = 0, dayVisitorCount = 0;

            for (const dev of group.acDevices) {
                const records = deviceDataMap.get(dev.device_id) || [];
                dayRunHours += calcAcRunHours(records, dayEnd);
            }
            for (const dev of group.envDevices) {
                const records = deviceDataMap.get(dev.device_id) || [];
                const { tempSum, tempCount } = calcEnvDeviceDaily(records);
                dayTempSum += tempSum;
                dayTempCount += tempCount;
            }
            for (const dev of group.customerDevices) {
                const { visitorSum, visitorCount } = calcCustomerDeviceDaily(deviceDataMap.get(dev.device_id) || []);
                dayVisitorSum += visitorSum;
                dayVisitorCount += visitorCount;
            }
            for (const dev of group.meterDevices) {
                dayEnergy += calcMeterDeviceDaily(deviceDataMap.get(dev.device_id) || []);
            }

            // 当日在馆人数均值 = 所有客流传感器当天采集值的平均
            const dayVisitor = dayVisitorCount > 0 ? dayVisitorSum : 0; // Math.round(dayVisitorSum / dayVisitorCount)

            // 累加到周汇总
            hallTotalRunHours += dayRunHours;
            if (dayTempCount > 0) { hallTempSum += dayTempSum; hallTempCount += dayTempCount; }
            hallTotalEnergy += dayEnergy;
            hallTotalVisitor += dayVisitor;

            tableList.push([
                formatDateStr(day),
                dayRunHours > 0 ? fmtNum(dayRunHours) + "h" : "——",
                dayTempCount > 0 ? fmtNum(dayTempSum / dayTempCount) : "——",
                dayVisitor > 0 ? String(dayVisitor) : "——",
                dayEnergy > 0 ? String(Math.round(dayEnergy * 100) / 100) : "——",
            ]);
        }

        // ===== 第四步：汇总各馆 =====
        const hallAvgTemp = hallTempCount > 0 ? hallTempSum / hallTempCount : null;
        const hallTempStr = hallAvgTemp != null ? fmtNum(hallAvgTemp) + "°C" : "——";
        const hallEnergyStr = fmtEnergy(hallTotalEnergy);
        const kllStr = hallTotalVisitor > 0 ? String(Math.round(hallTotalVisitor)) : "——";

        dataTotal[hallKey] = { nh: hallEnergyStr, kll: kllStr, jw: hallTempStr };
        runDatas[hallName] = {
            rjnh: hallTotalEnergy > 0 ? String(Math.round(hallTotalEnergy * 100) / 100) + " kWh" : "——",
            tableData: [{ titleList: TABLE_TITLE_LIST, tableList }],
            totalData: [
                "周累计",
                hallTotalRunHours > 0 ? fmtNum(hallTotalRunHours) + "h" : "——",
                hallTempStr,
                kllStr,
                hallEnergyStr,
            ],
        };

        overallEnergy += hallTotalEnergy;
        overallVisitor += hallTotalVisitor;
        if (hallTempCount > 0) {
            overallTempSum += hallTempSum;
            overallTempCount += hallTempCount;
        }

        if (hallTotalRunHours > 0) {
            console.log(`[周报告JSON] ${hallName} 空调周运行时长: ${Math.round(hallTotalRunHours)}h`);
        }
    }

    // ===== 第五步：整体汇总 + 评价 =====
    dataTotal.ztyx = {
        nh: fmtEnergy(overallEnergy),
        kll: overallVisitor > 0 ? String(Math.round(overallVisitor)) : "——",
        jw: overallTempCount > 0
            ? fmtNum(overallTempSum / overallTempCount) + "°C"
            : "——",
    };

    const evalMap: any = {};
    for (let i = 0; i < HALL_NAMES.length; i++) {
        const group = hallDeviceGroups.get(HALL_NAMES[i])!;
        const faultCount = group.allDevices.filter(d => faultSet.has(d.device_id)).length;
        evalMap[HALL_NAMES[i]] = faultCount === 0 ? "优秀" : faultCount <= 2 ? "合格" : "待改善";
    }
    dataTotal.ztpj = evalMap;

    return { timer, dataTotal, runDatas };
}

// ======================= 九合一环境监测指标 7 天均值 =======================

/** 九合一核心指标（去掉 pir 人体感应 和 o3 臭氧） */
const ENV_INDICATOR_KEYS = [
    { key: "co2",         name: "二氧化碳", unit: "ppm" },
    { key: "pm10",        name: "PM10",     unit: "μg/m³" },
    { key: "pm2_5",       name: "PM2.5",    unit: "μg/m³" },
    { key: "hcho",        name: "甲醛",      unit: "mg/m³" },
    { key: "tvoc",        name: "TVOC",     unit: "mg/m³" },
    { key: "temperature", name: "温度",      unit: "℃" },
    { key: "humidity",    name: "湿度",      unit: "%" },
    { key: "pressure",    name: "气压",      unit: "hPa" },
    { key: "light_level", name: "光照度",    unit: "lux" },
];

/**
 * 查询九合一环境监测指标的 7 天均值（A馆 / B馆 / C馆）
 * 对每个馆的环境监测设备，取近 7 天所有上报数据的算术平均
 */
export async function getEnvIndicatorsWeeklyAvg(): Promise<any> {
    // 1. 计算七天时间范围
    const now = new Date();
    const end = new Date(now);
    end.setHours(23, 59, 59, 999);
    const start = new Date(now);
    start.setDate(now.getDate() - 6);
    start.setHours(0, 0, 0, 0);

    const from = formatLocalTime(start);
    const to = formatLocalTime(end);
    const timer = `${formatChineseDate(start)} — ${formatChineseDate(end)}`;

    console.log(`[九合一七日均值] 查询范围: ${timer}`);

    // 2. 并行查询三馆区域
    const hallRegionMap = await queryHallRegions();

    // 3. 并行查询三馆的环境监测设备
    const hallDeviceGroups = await Promise.all(
        HALL_NAMES.map(h => queryHallDeviceGroup(hallRegionMap.get(h) || []))
    );

    // 4. 并行查询三馆近 7 天的设备数据
    const hallResults = await Promise.all(
        hallDeviceGroups.map(async (group) => {
            const envDeviceIds = group.envDevices.map(d => d.device_id);
            if (envDeviceIds.length === 0) return null;

            const dayDataRes = await selectDataListByParam(TABLENAME.设备数据表, {
                device_id: { "%in%": envDeviceIds },
                device_time: { "%gte%": from, "%lte%": to },
            }, ["device_id", "data"]);

            return dayDataRes.data || [];
        })
    );

    // 5. 计算每个馆的各指标均值
    const result: any = { timer };

    for (let idx = 0; idx < HALL_NAMES.length; idx++) {
        const hallName = HALL_NAMES[idx];
        const records = hallResults[idx];
        const indicators: any = {};

        if (!records || records.length === 0) {
            // 无数据填 null
            for (const ik of ENV_INDICATOR_KEYS) {
                indicators[ik.key] = { name: ik.name, value: null, unit: ik.unit };
            }
        } else {
            // 统计各指标累加值和计数
            const sums: { [key: string]: number } = {};
            const counts: { [key: string]: number } = {};
            for (const ik of ENV_INDICATOR_KEYS) {
                sums[ik.key] = 0;
                counts[ik.key] = 0;
            }
            for (const rec of records) {
                const d = rec.data || {};
                for (const ik of ENV_INDICATOR_KEYS) {
                    const v = d[ik.key];
                    if (v !== undefined && v !== null && typeof v === "number") {
                        sums[ik.key] += v;
                        counts[ik.key]++;
                    }
                }
            }
            for (const ik of ENV_INDICATOR_KEYS) {
                const avg = counts[ik.key] > 0
                    ? Math.round((sums[ik.key] / counts[ik.key]) * 100) / 100
                    : null;
                indicators[ik.key] = { name: ik.name, value: avg, unit: ik.unit };
            }
        }

        result[hallName] = { deviceCount: hallDeviceGroups[idx].envDevices.length, recordCount: records?.length || 0, indicators };
    }

    console.log(`[九合一七日均值] 完成`);
    return result;
}

// ======================= 近 7 天故障信息（按 fault_code 分组） =======================

const STATUS_MAP: { [key: number]: string } = { 0: "未处理", 1: "处理中", 2: "已解决" };
const LEVEL_MAP: { [key: number]: string } = { 1: "一级", 2: "二级", 3: "三级" };

/**
 * 查询近 7 天故障信息，按 fault_code 分组
 * 每组展示：故障代码、风险内容、报警时间、处理状态、报警设备
 */
export async function getFaultInfoLast7Days(): Promise<any> {
    const now = new Date();
    const end = new Date(now);
    end.setHours(23, 59, 59, 999);
    const start = new Date(now);
    start.setDate(now.getDate() - 6);
    start.setHours(0, 0, 0, 0);

    const from = formatLocalTime(start);
    const to = formatLocalTime(end);
    const timer = `${formatChineseDate(start)} — ${formatChineseDate(end)}`;

    console.log(`[近7天故障] 查询范围: ${timer}`);

    // 1. 查询近 7 天故障记录（按发生时间倒序）
    const faultRes = await selectDataListByParam(TABLENAME.设备故障表, {
        occurred_time: { "%gte%": from, "%lte%": to },
        "%orderDesc%": "occurred_time",
    });
    const faultRecords = faultRes.data || [];

    if (faultRecords.length === 0) {
        return { timer, totalCount: 0, groups: [] };
    }

    // 2. 收集所有 device_id，查询设备名称
    const deviceIds = [...new Set(faultRecords.map((f: any) => f.device_id).filter(Boolean))];
    let deviceNameMap: Map<string, string> = new Map();
    if (deviceIds.length > 0) {
        const devRes = await selectDataListByParam(TABLENAME.设备表, {
            device_id: { "%in%": deviceIds },
        }, ["device_id", "device_name"]);
        for (const d of (devRes.data || [])) {
            deviceNameMap.set(d.device_id, d.device_name || d.device_id);
        }
    }

    // 3. 按 fault_code 分组
    const groupMap: { [code: string]: any[] } = {};
    for (const f of faultRecords) {
        const code = f.fault_code || "未分类";
        if (!groupMap[code]) groupMap[code] = [];
        groupMap[code].push({
            id: f.id,
            faultType: f.fault_type || "",
            faultCode: code,
            faultDesc: f.fault_description || "",
            alarmTime: f.occurred_time
                ? (typeof f.occurred_time === "string" ? f.occurred_time : formatLocalTime(new Date(f.occurred_time)))
                : "",
            status: f.status ?? 0,
            statusText: STATUS_MAP[f.status] ?? "未知",
            level: f.level ?? 0,
            levelText: LEVEL_MAP[f.level] ?? "未知",
            deviceId: f.device_id,
            deviceName: deviceNameMap.get(f.device_id) || f.device_id || "",
        });
    }

    // 4. 构建分组结果
    const groups = Object.entries(groupMap)
        .sort((a, b) => b[1].length - a[1].length) // 按故障数量降序
        .map(([code, items]) => ({
            faultCode: code,
            count: items.length,
            items,
        }));

    const totalCount = faultRecords.length;

    console.log(`[近7天故障] 共 ${totalCount} 条，${groupMap.size} 种故障码`);
    return { timer, totalCount, groupCount: Object.keys(groupMap).length, groups };
}
