// Applying health events in place.
//
// health.changed / health.stale already carry the new value in their payload,
// so a view that renders health does not need to refetch anything: it can
// patch the one entity it already holds. Refetching the whole fleet because a
// single container went degraded costs a full round trip, re-runs the parent
// grouping, and churns the table on every transition — for information the
// event had already delivered.
//
// NOTE: match on entity_id, never on data.slug. The scheduler emits
// health.changed with entity_id = the observed entity but data.slug = the
// *check's* slug (e.g. "check:ping:host:hubris:0"), so the slug in the
// payload does not identify the thing whose health changed.

import type { Entity, EntityHealth } from '$lib/api'
import type { OikosEvent } from '$lib/stores/events'

const HEALTH_EVENTS = new Set(['health.changed', 'health.stale'])

export function isHealthEvent(ev: OikosEvent): boolean {
  return HEALTH_EVENTS.has(ev.type)
}

/** The new health an event reports, or null if it isn't a usable health event. */
export function healthFromEvent(ev: OikosEvent): EntityHealth | null {
  if (!isHealthEvent(ev) || !ev.entity_id) return null
  const to = (ev.data as Record<string, unknown> | undefined)?.to
  return typeof to === 'string' ? (to as EntityHealth) : null
}

/**
 * Returns a copy of `list` with the event's entity patched, or the original
 * array when the event doesn't apply — so callers can assign unconditionally
 * without forcing a re-render for an entity they aren't showing.
 */
export function applyHealthEvent(list: Entity[], ev: OikosEvent): Entity[] {
  const health = healthFromEvent(ev)
  if (!health) return list
  const i = list.findIndex((e) => e.id === ev.entity_id)
  if (i < 0) return list
  if (list[i].health === health) return list
  const next = list.slice()
  // ev.ts is when the check ran, which is exactly what "checked N ago" means.
  next[i] = { ...next[i], health, last_check_at: ev.ts }
  return next
}

/** Single-entity form, for a detail view holding one entity. */
export function applyHealthEventTo(entity: Entity | null, ev: OikosEvent): Entity | null {
  if (!entity || ev.entity_id !== entity.id) return entity
  const health = healthFromEvent(ev)
  if (!health || entity.health === health) return entity
  return { ...entity, health, last_check_at: ev.ts }
}
