export function evaluateSecurityAlertPolicy(result, profile, now = new Date()) { if (!result?.notify) return { send: false, reason: 'agent_declined' }; if (!profile) return { send: true, reason: 'no_profile' }; const priority = ['routine', 'priority', 'flash'].includes(result.priority) ? result.priority : 'routine'; const preference = profile.alertPreference || 'important'; if (preference === 'critical_only' && priority !== 'flash') { return { send: false, reason: 'critical_only' }; } if (preference === 'important' && priority === 'routine') { return { send: false, reason: 'routine_suppressed' }; } if (priority !== 'flash' && isWithinQuietHours(profile.quietHours, profile.timezone, now)) { return { send: false, reason: 'quiet_hours' }; } return { send: true, reason: 'allowed' }; } export function isWithinQuietHours(value, timezone, now = new Date()) { const match = String(value || '').match(/^([01]\d|2[0-3]):([0-5]\d)-([01]\d|2[0-3]):([0-5]\d)$/); if (!match) return false; const localMinutes = minutesInTimezone(now, timezone); if (localMinutes == null) return false; const start = Number(match[1]) * 60 + Number(match[2]); const end = Number(match[3]) * 60 + Number(match[4]); if (start === end) return true; return start < end ? localMinutes >= start && localMinutes < end : localMinutes >= start || localMinutes < end; } function minutesInTimezone(date, timezone) { try { const parts = new Intl.DateTimeFormat('en-GB', { timeZone: timezone || 'UTC', hour: '2-digit', minute: '2-digit', hourCycle: 'h23', }).formatToParts(date); const hour = Number(parts.find(part => part.type === 'hour')?.value); const minute = Number(parts.find(part => part.type === 'minute')?.value); return Number.isFinite(hour) && Number.isFinite(minute) ? hour * 60 + minute : null; } catch { return null; } }