package wang.yaojia.webterm.wire

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * One activity-timeline entry from `GET /live-sessions/:id/events` (FROZEN shape, plan §3.1;
 * mirrors `src/types.ts:434-439` and iOS `WireProtocol.TimelineEvent`).
 *
 * The server derives [eventClass] semantically (`src/types.ts:429`: tool/waiting/done/stuck/
 * user) — the client never re-derives it from hook names. [eventClass] stays a raw String so
 * the SHAPE decodes even for future/unknown classes; consumers drop unknowns via
 * [hasKnownClass]. The tolerant list decode (per-element drop, non-array -> empty) is A8.
 */
@Serializable
public data class TimelineEvent(
    /** Server ingest timestamp (ms since epoch). */
    val at: Long,
    /** Server-derived semantic class; see [KNOWN_CLASSES]. JSON key is `class`. */
    @SerialName("class") val eventClass: String,
    /** Sanitized tool name (server-side: <=200 chars, control chars stripped). */
    val toolName: String? = null,
    /** Server-derived human phrase ("ran Bash", "edited 3 files"). */
    val label: String,
) {
    /** True when [eventClass] is one the server currently emits. */
    public val hasKnownClass: Boolean get() = eventClass in KNOWN_CLASSES

    public companion object {
        /** The server's `TimelineClass` union (`src/types.ts:429`). */
        public val KNOWN_CLASSES: Set<String> = setOf("tool", "waiting", "done", "stuck", "user")
    }
}
