use serde::{Deserialize, Serialize};
use crate::ids::{SurfaceId, WorkspaceId};

/// The subset of activity that lands in the event log.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum EventKind {
    Done,
    Wait,
    Error,
    Exit,
}

/// One logged event. Workspace name and agent label are denormalized so the
/// feed stays displayable after the surface or workspace is closed.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct EventRecord {
    pub id: u64,
    pub surface_id: SurfaceId,
    pub workspace_id: WorkspaceId,
    pub workspace_name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub agent_label: Option<String>,
    pub kind: EventKind,
    pub ts: u64,
    pub read: bool,
}

/// What a `mark_read` request targets.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "target", content = "value", rename_all = "snake_case")]
pub enum MarkReadTarget {
    All,
    Ids(Vec<u64>),
    Surface(SurfaceId),
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn event_kind_serializes_lowercase() {
        assert_eq!(serde_json::to_string(&EventKind::Done).unwrap(), r#""done""#);
        assert_eq!(serde_json::to_string(&EventKind::Exit).unwrap(), r#""exit""#);
    }

    #[test]
    fn event_record_round_trips() {
        let r = EventRecord {
            id: 7,
            surface_id: SurfaceId("s_1".into()),
            workspace_id: WorkspaceId("w_1".into()),
            workspace_name: "infra".into(),
            agent_label: Some("claude".into()),
            kind: EventKind::Error,
            ts: 1_700_000_000_000,
            read: false,
        };
        let back: EventRecord = serde_json::from_str(&serde_json::to_string(&r).unwrap()).unwrap();
        assert_eq!(back, r);
    }

    #[test]
    fn mark_read_target_variants_serialize() {
        assert_eq!(serde_json::to_string(&MarkReadTarget::All).unwrap(), r#"{"target":"all"}"#);
        assert_eq!(
            serde_json::to_string(&MarkReadTarget::Ids(vec![1, 2])).unwrap(),
            r#"{"target":"ids","value":[1,2]}"#
        );
        let s = MarkReadTarget::Surface(SurfaceId("s_9".into()));
        assert_eq!(serde_json::to_string(&s).unwrap(), r#"{"target":"surface","value":"s_9"}"#);
        let back: MarkReadTarget = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
        assert_eq!(back, s);
    }
}
