"use client"; import { createContext, useContext, useState, useEffect, useMemo } from "react"; import { THRESHOLDS } from "@/lib/thresholds"; const LS_KEY = "bms_thresholds"; /** Subset of THRESHOLDS that the Settings page allows overriding */ export interface ThresholdOverrides { temp?: { warn?: number; critical?: number }; humidity?: { low?: number; warn?: number; critical?: number }; power?: { warn?: number; critical?: number }; } /** Mutable version of THRESHOLDS for runtime use */ export interface MergedThresholds { temp: { warn: number; critical: number }; humidity: { low: number; warn: number; critical: number }; dewPoint: { warn: number }; power: { warn: number; critical: number }; rackPower: { warn: number; critical: number; rated: number }; filter: { warn: number; critical: number; ratePerDay: number; replaceAt: number }; cop: { warn: number }; compressor: { warn: number; critical: number }; battery: { warn: number; critical: number }; fuel: { warn: number; critical: number }; ups: { loadWarn: number; loadCritical: number }; pue: { target: number; warn: number; critical: number }; phaseImbalance: { warn: number; critical: number }; network: { cpuWarn: number; cpuCritical: number; memWarn: number; memCritical: number; tempWarn: number; tempCritical: number }; ashrae: { tempMin: number; tempMax: number; rhMin: number; rhMax: number }; } interface ThresholdContextValue { thresholds: MergedThresholds; setThresholds: (patch: ThresholdOverrides) => void; } const ThresholdContext = createContext(null); function loadOverrides(): ThresholdOverrides { if (typeof window === "undefined") return {}; try { const raw = localStorage.getItem(LS_KEY); return raw ? JSON.parse(raw) : {}; } catch { return {}; } } function merge(overrides: ThresholdOverrides): MergedThresholds { return { temp: { warn: THRESHOLDS.temp.warn, critical: THRESHOLDS.temp.critical, ...overrides.temp }, humidity: { low: THRESHOLDS.humidity.low, warn: THRESHOLDS.humidity.warn, critical: THRESHOLDS.humidity.critical, ...overrides.humidity }, dewPoint: { warn: THRESHOLDS.dewPoint.warn }, power: { warn: THRESHOLDS.power.warn, critical: THRESHOLDS.power.critical, ...overrides.power }, rackPower: { warn: THRESHOLDS.rackPower.warn, critical: THRESHOLDS.rackPower.critical, rated: THRESHOLDS.rackPower.rated }, filter: { warn: THRESHOLDS.filter.warn, critical: THRESHOLDS.filter.critical, ratePerDay: THRESHOLDS.filter.ratePerDay, replaceAt: THRESHOLDS.filter.replaceAt }, cop: { warn: THRESHOLDS.cop.warn }, compressor: { warn: THRESHOLDS.compressor.warn, critical: THRESHOLDS.compressor.critical }, battery: { warn: THRESHOLDS.battery.warn, critical: THRESHOLDS.battery.critical }, fuel: { warn: THRESHOLDS.fuel.warn, critical: THRESHOLDS.fuel.critical }, ups: { loadWarn: THRESHOLDS.ups.loadWarn, loadCritical: THRESHOLDS.ups.loadCritical }, pue: { target: THRESHOLDS.pue.target, warn: THRESHOLDS.pue.warn, critical: THRESHOLDS.pue.critical }, phaseImbalance: { warn: THRESHOLDS.phaseImbalance.warn, critical: THRESHOLDS.phaseImbalance.critical }, network: { cpuWarn: THRESHOLDS.network.cpuWarn, cpuCritical: THRESHOLDS.network.cpuCritical, memWarn: THRESHOLDS.network.memWarn, memCritical: THRESHOLDS.network.memCritical, tempWarn: THRESHOLDS.network.tempWarn, tempCritical: THRESHOLDS.network.tempCritical }, ashrae: { tempMin: THRESHOLDS.ashrae.tempMin, tempMax: THRESHOLDS.ashrae.tempMax, rhMin: THRESHOLDS.ashrae.rhMin, rhMax: THRESHOLDS.ashrae.rhMax }, }; } export function ThresholdProvider({ children }: { children: React.ReactNode }) { const [overrides, setOverrides] = useState({}); useEffect(() => { setOverrides(loadOverrides()); }, []); const thresholds = useMemo(() => merge(overrides), [overrides]); function setThresholds(patch: ThresholdOverrides) { const next: ThresholdOverrides = { temp: { ...overrides.temp, ...patch.temp }, humidity: { ...overrides.humidity, ...patch.humidity }, power: { ...overrides.power, ...patch.power }, }; setOverrides(next); localStorage.setItem(LS_KEY, JSON.stringify(next)); } return ( {children} ); } export function useThresholds(): ThresholdContextValue { const ctx = useContext(ThresholdContext); if (!ctx) throw new Error("useThresholds must be used inside ThresholdProvider"); return ctx; }