use serde::{Deserialize, Serialize};
use serde_json::Value;
use time::OffsetDateTime;

use crate::ids::{AgentId, OperationId, WorkspaceId};

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AgentStatus {
    Draft,
    Published,
    Archived,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Agent {
    pub id: AgentId,
    pub workspace_id: WorkspaceId,
    pub slug: String,
    pub display_name: String,
    pub description: String,
    pub status: AgentStatus,
    pub current_draft_version: u32,
    pub latest_published_version: Option<u32>,
    #[serde(with = "time::serde::rfc3339")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::rfc3339")]
    pub updated_at: OffsetDateTime,
    #[serde(default, with = "time::serde::rfc3339::option")]
    pub published_at: Option<OffsetDateTime>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentVersion {
    pub agent_id: AgentId,
    pub version: u32,
    pub status: AgentStatus,
    pub instructions: Value,
    pub tool_selection_policy: Value,
    #[serde(with = "time::serde::rfc3339")]
    pub created_at: OffsetDateTime,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentOperationBinding {
    pub operation_id: OperationId,
    pub operation_version: u32,
    pub tool_name: String,
    pub tool_title: String,
    pub tool_description_override: Option<String>,
    pub enabled: bool,
}

#[cfg(test)]
mod tests {
    use serde_json::json;
    use time::{OffsetDateTime, format_description::well_known::Rfc3339};

    use super::{Agent, AgentStatus, AgentVersion};
    use crate::ids::{AgentId, WorkspaceId};

    #[test]
    fn agent_serializes_timestamps_as_rfc3339() {
        let agent = Agent {
            id: AgentId::new("agent_01"),
            workspace_id: WorkspaceId::new("ws_01"),
            slug: "triage".to_owned(),
            display_name: "Triage".to_owned(),
            description: "Triage agent".to_owned(),
            status: AgentStatus::Published,
            current_draft_version: 2,
            latest_published_version: Some(2),
            created_at: OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap(),
            updated_at: OffsetDateTime::parse("2026-03-25T12:05:00Z", &Rfc3339).unwrap(),
            published_at: Some(OffsetDateTime::parse("2026-03-25T12:10:00Z", &Rfc3339).unwrap()),
        };

        let value = serde_json::to_value(&agent).unwrap();

        assert_eq!(value["created_at"], json!("2026-03-25T12:00:00Z"));
        assert_eq!(value["updated_at"], json!("2026-03-25T12:05:00Z"));
        assert_eq!(value["published_at"], json!("2026-03-25T12:10:00Z"));
    }

    #[test]
    fn agent_version_deserializes_created_at_from_rfc3339() {
        let version: AgentVersion = serde_json::from_value(json!({
            "agent_id": "agent_01",
            "version": 1,
            "status": "draft",
            "instructions": {"system": "triage"},
            "tool_selection_policy": {"mode": "allow_list"},
            "created_at": "2026-03-25T12:00:00Z"
        }))
        .unwrap();

        assert_eq!(
            version.created_at,
            OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap()
        );
    }
}
