package com.correx.core.events.events

import com.correx.core.events.types.SessionId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * The organs the health monitor watches (observability-spec §4). Each is small, paranoid, and
 * continuous; a state change for any one is recorded as a [HealthDegradedEvent] / [HealthRestoredEvent]
 * so health is observable, replayable, and renderable like every other fact in the log.
 */
@Serializable
enum class HealthSubject {
    /** Local inference process: liveness + tokens/sec degradation (KV-cache pressure, thermal throttle). */
    LLAMA_SERVER,

    /** The append-only event log: append latency + fsync health. The organ that must never lie. */
    EVENT_STORE,

    /** CAS + log size and growth rate. Append-only means monotonic growth; warn before the 2am surprise. */
    DISK,
}

/**
 * A monitored [subject] crossed from healthy into degraded. Emitted only on the edge (the monitor
 * holds the last status per subject), so the log records transitions, not every poll. The
 * environment observation that triggered it is captured here at observe-time (Hard Invariant #9):
 * replay reads this recorded fact and never re-probes the filesystem/process/store.
 *
 * [metric] names the dimension that crossed (e.g. `total_bytes`, `growth_bytes_per_min`);
 * [observedValue] is its value at the edge; [threshold] is the watermark it crossed.
 */
@Serializable
@SerialName("HealthDegraded")
data class HealthDegradedEvent(
    val sessionId: SessionId,
    val subject: HealthSubject,
    val metric: String,
    val observedValue: Long,
    val threshold: Long,
    val detail: String,
) : EventPayload

/**
 * A monitored [subject] recovered from degraded back to healthy. Edge-triggered counterpart to
 * [HealthDegradedEvent]; [observedValue] is the [metric] value that brought it back under the line.
 */
@Serializable
@SerialName("HealthRestored")
data class HealthRestoredEvent(
    val sessionId: SessionId,
    val subject: HealthSubject,
    val metric: String,
    val observedValue: Long,
    val detail: String,
) : EventPayload
