/**
 * Weather Alert Advice Cache.
 *
 * Persists the AI-enriched short actionable advice per alert signature. The
 * same warning reuses its advice for the life of the event; changed/escalated
 * warnings receive a new signature. Entries are pruned when no current warning
 * carries their signature.
 */
import { createJsonFileCache } from './jsonFileCache';
import { asTrimmedString, isRecord } from './serviceUtils';

export type AlertAdviceEntry = { advice: string; signature: string };

const UNSAFE_RECORD_KEYS = new Set(['__proto__', 'prototype', 'constructor']);

function decodeAdviceCache(value: unknown): Record<string, string> | null {
  if (!isRecord(value)) return null;
  const out: Record<string, string> = {};
  for (const [rawSignature, rawAdvice] of Object.entries(value)) {
    const signature = asTrimmedString(rawSignature, 500);
    if (!signature || UNSAFE_RECORD_KEYS.has(signature)) continue;
    const advice = asTrimmedString(rawAdvice, 1_000);
    if (advice) out[signature] = advice;
  }
  return out;
}

const adviceCache = createJsonFileCache<Record<string, string>>(
  'weather-alert-advice-cache.json',
  () => ({}),
  decodeAdviceCache,
);

export function loadAlertAdviceCache(): Promise<Record<string, string>> {
  return adviceCache.load();
}

/** Persist the entire cache (replace). Serialized and snapshotted at call time. */
export function saveAlertAdviceCache(cache: Record<string, string>): Promise<void> {
  return adviceCache.save(decodeAdviceCache(cache) ?? {});
}

/** Keep only advice whose signature is still present in the current alert set. */
export function pruneAlertAdviceCache(
  cache: Record<string, string>,
  activeSignatures: Set<string>,
): Record<string, string> {
  const validCache = decodeAdviceCache(cache) ?? {};
  const active = activeSignatures instanceof Set ? activeSignatures : new Set<string>();
  const next: Record<string, string> = {};
  for (const [signature, advice] of Object.entries(validCache)) {
    if (active.has(signature)) next[signature] = advice;
  }
  return next;
}
