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

/** 默认关机时间 23:00（分钟数） */
const DEFAULT_OFF_MINUTES = 23 * 60;
/** 默认开机时间 05:00（分钟数） */
const DEFAULT_ON_MINUTES = 5 * 60;

/**
 * 将 HH:mm:ss 或 HH:mm 格式的时间转为分钟数
 */
function timeToMinutes(timeStr: string): number {
    const parts = timeStr.split(':').map(Number);
    return parts[0] * 60 + (parts[1] || 0);
}

// ===== 内存缓存 =====
interface CacheEntry {
    result: boolean;
    expireAt: number; // 过期时间戳 ms
}
const offPeriodCache = new Map<string, CacheEntry>();
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 分钟

function getCacheKey(deviceId: string, regionKey: number | string): string {
    return `${deviceId}_${regionKey}`;
}

/** 清空所有缓存 */
export function clearOffPeriodCache(): void {
    offPeriodCache.clear();
    console.log(`[scheduleStatus] 缓存已清空`);
}

/** 清空指定设备的缓存 */
export function clearOffPeriodCacheForDevice(deviceId: string): void {
    const prefix = `${deviceId}_`;
    for (const key of offPeriodCache.keys()) {
        if (key.startsWith(prefix)) {
            offPeriodCache.delete(key);
        }
    }
}

/**
 * 判断设备当前是否处于"关闭/休眠时段"
 *
 * 逻辑：
 * 1. 查 schedule_device 表，获取设备关联的日程 ID（按 device_id 或 region_key 匹配）
 * 2. 查 schedule 表，获取 ac_control=on/off 且设置了 schedule_time 的日程
 * 3. 若日程中没有 on 时间 → 用默认 05:00；没有 off 时间 → 用默认 23:00
 * 4. 找到当前时间点之前最近的一次操作（on/off），若为 off 则处于关闭时段
 * 5. 结果缓存 5 分钟
 *
 * @returns true 表示当前处于关闭时段，应跳过联动
 */
export async function isInOffPeriod(deviceId: string, regionKey: number): Promise<boolean> {
    const cacheKey = getCacheKey(deviceId, regionKey);
    const cached = offPeriodCache.get(cacheKey);

    // 缓存命中且未过期
    if (cached && cached.expireAt > Date.now()) {
        return cached.result;
    }

    const now = new Date();
    const nowMinutes = now.getHours() * 60 + now.getMinutes();

    try {
        // 1. 查 schedule_device：匹配 device_id 或 (region_key 且 device_id 为空，即区域级日程)
        const sdResult = await selectDataListByParam(
            TABLENAME.日程设备关联表,
            {
                "%or%": [
                    { device_id: deviceId },
                    { region_key: regionKey, device_id: "" },
                ],
            },
            ["schedule_id"],
        );

        const scheduleIds = [...new Set((sdResult.data as any[]).map((d: any) => d.schedule_id))];

        // 2. 无关联日程 → 使用默认 23:00-05:00 判断
        if (scheduleIds.length === 0) {
            const result = nowMinutes >= DEFAULT_OFF_MINUTES || nowMinutes < DEFAULT_ON_MINUTES;
            offPeriodCache.set(cacheKey, { result, expireAt: Date.now() + CACHE_TTL_MS });
            console.log(
                `[scheduleStatus] 设备 ${deviceId} 无关联日程，使用默认时段(23:00-05:00)，当前${result ? '关闭' : '开启'}时段`,
            );
            return result;
        }

        // 3. 查 schedule 表：有 schedule_time 且 ac_control 为 on/off
        const schResult = await selectDataListByParam(
            TABLENAME.日程表,
            {
                id: { "%in%": scheduleIds },
                schedule_time: { "%ne%": null },
                ac_control: { "%in%": ["on", "off"] },
            },
            ["ac_control", "schedule_time"],
        );

        const schedules = schResult.data as any[];
        let hasOnSchedule = false;
        let hasOffSchedule = false;
        let latestOffBeforeNow = -1; // 今天当前时间之前最近的 off，不跨天时
        let latestOnBeforeNow = -1;
        const allOffMinutes: number[] = [];
        const allOnMinutes: number[] = [];

        for (const s of schedules) {
            const minutes = timeToMinutes(s.schedule_time);
            if (s.ac_control === "off") {
                hasOffSchedule = true;
                allOffMinutes.push(minutes);
                if (minutes <= nowMinutes && minutes > latestOffBeforeNow) {
                    latestOffBeforeNow = minutes;
                }
            } else if (s.ac_control === "on") {
                hasOnSchedule = true;
                allOnMinutes.push(minutes);
                if (minutes <= nowMinutes && minutes > latestOnBeforeNow) {
                    latestOnBeforeNow = minutes;
                }
            }
        }

        // 4. 构建完整的 on/off 时间点列表（含默认值兜底）
        const actions: { time: number; type: "on" | "off" }[] = [];

        // 加入日程中的时间点
        for (const min of allOffMinutes) {
            actions.push({ time: min, type: "off" });
        }
        for (const min of allOnMinutes) {
            actions.push({ time: min, type: "on" });
        }

        // 兜底：日程中没有 on → 默认 05:00 开机
        if (!hasOnSchedule) {
            actions.push({ time: DEFAULT_ON_MINUTES, type: "on" });
        }
        // 兜底：日程中没有 off → 默认 23:00 关机
        if (!hasOffSchedule) {
            actions.push({ time: DEFAULT_OFF_MINUTES, type: "off" });
        }

        // 按时间排序
        actions.sort((a, b) => a.time - b.time);

        // 5. 找到当前时间之前最近的一次操作
        // 如果今天没有 ≤ nowMinutes 的操作，说明所有操作都在未来，
        // 取昨天最后一个操作（即 actions 中时间最大的那个，视为跨天）
        let lastAction: { time: number; type: "on" | "off" } | null = null;

        for (let i = actions.length - 1; i >= 0; i--) {
            if (actions[i].time <= nowMinutes) {
                lastAction = actions[i];
                break;
            }
        }

        if (lastAction === null) {
            // 所有操作都在当前时间之后 → 取昨天的最后一个操作
            // 最后一条就是时间最大的，视为昨天执行的操作
            const yesterdayAction = actions[actions.length - 1];
            const result = yesterdayAction.type === "off";
            offPeriodCache.set(cacheKey, { result, expireAt: Date.now() + CACHE_TTL_MS });
            const offTime = Math.floor(yesterdayAction.time / 60);
            console.log(
                `[scheduleStatus] 设备 ${deviceId} 跨天，昨天最后操作为 ${yesterdayAction.type}(${offTime}:00)，当前${result ? '关闭' : '开启'}时段`,
            );
            return result;
        }

        const result = lastAction.type === "off";
        offPeriodCache.set(cacheKey, { result, expireAt: Date.now() + CACHE_TTL_MS });
        const actionHour = Math.floor(lastAction.time / 60);
        console.log(
            `[scheduleStatus] 设备 ${deviceId} 最近操作为 ${lastAction.type}(${actionHour}:00)，当前${result ? '关闭' : '开启'}时段`,
        );
        return result;
    } catch (error) {
        console.error(`[scheduleStatus] 查询设备 ${deviceId} 日程失败，降级为默认 23-05:`, error);
        const result = nowMinutes >= DEFAULT_OFF_MINUTES || nowMinutes < DEFAULT_ON_MINUTES;
        return result;
    }
}
