package com.correx.apps.server.health

import com.correx.core.events.events.HealthDegradedEvent
import com.correx.core.events.events.HealthRestoredEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.sessions.projections.Projection

/**
 * Pure fold deriving [HealthState] from the health events recorded on the system session
 * (observability-spec §4: "health states are events ... renderable like everything else").
 *
 * Records no new events and reads only the edge events the [HealthMonitor] already emits;
 * a disposable read-model (Hard Invariant #2). Because health is event-sourced, the monitor
 * can seed its in-memory last-status from this projection across a restart, and replay
 * reconstructs the exact health timeline without re-probing the environment (Invariant #8/#9).
 */
class HealthProjection : Projection<HealthState> {

    override fun initial(): HealthState = HealthState()

    override fun apply(state: HealthState, event: StoredEvent): HealthState =
        when (val payload = event.payload) {
            is HealthDegradedEvent -> state.with(
                payload.subject,
                SubjectHealth(
                    status = HealthStatus.DEGRADED,
                    metric = payload.metric,
                    observedValue = payload.observedValue,
                    detail = payload.detail,
                    since = event.metadata.timestamp,
                ),
            )
            is HealthRestoredEvent -> state.with(
                payload.subject,
                SubjectHealth(
                    status = HealthStatus.HEALTHY,
                    metric = payload.metric,
                    observedValue = payload.observedValue,
                    detail = payload.detail,
                    since = event.metadata.timestamp,
                ),
            )
            else -> state
        }
}
