//! Message types shared between producer and worker.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageEnvelope {
    pub id: Uuid,
    pub dedup_key: Option<String>,
    pub room_id: Uuid,
    pub sender_type: String,
    pub sender_id: Option<Uuid>,
    /// AI model ID — set when sender_type = "ai", used for display name lookups.
    pub model_id: Option<Uuid>,
    pub thread_id: Option<Uuid>,
    pub in_reply_to: Option<Uuid>,
    pub content: String,
    pub content_type: String,
    pub send_at: DateTime<Utc>,
    pub seq: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageEvent {
    pub id: Uuid,
    pub room_id: Uuid,
    pub sender_type: String,
    pub sender_id: Option<Uuid>,
    pub thread_id: Option<Uuid>,
    pub in_reply_to: Option<Uuid>,
    pub content: String,
    pub content_type: String,
    pub send_at: DateTime<Utc>,
    pub seq: i64,
    pub display_name: Option<String>,
    /// Present when this event carries reaction updates for the message.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reactions: Option<Vec<ReactionGroup>>,
    /// Target message ID for reaction update events.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message_id: Option<Uuid>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReactionGroup {
    pub emoji: String,
    pub count: i32,
    pub reacted_by_me: bool,
    /// Stored as strings (UUIDs) to match the frontend's `users: string[]` type.
    pub users: Vec<String>,
}

impl From<RoomMessageEnvelope> for RoomMessageEvent {
    fn from(e: RoomMessageEnvelope) -> Self {
        Self {
            id: e.id,
            room_id: e.room_id,
            sender_type: e.sender_type,
            sender_id: e.sender_id,
            thread_id: e.thread_id,
            in_reply_to: e.in_reply_to,
            content: e.content,
            content_type: e.content_type,
            send_at: e.send_at,
            seq: e.seq,
            display_name: None,
            reactions: None,
            message_id: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectRoomEvent {
    pub event_type: String,
    pub project_id: Uuid,
    pub room_id: Option<Uuid>,
    pub category_id: Option<Uuid>,
    pub message_id: Option<Uuid>,
    pub seq: Option<i64>,
    pub timestamp: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomMessageStreamChunkEvent {
    pub message_id: Uuid,
    pub room_id: Uuid,
    pub content: String,
    pub done: bool,
    pub error: Option<String>,
    /// Human-readable AI model name (e.g. "Claude 3.5 Sonnet") for display.
    pub display_name: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailEnvelope {
    pub id: Uuid,
    pub to: String,
    pub subject: String,
    pub body: String,
    pub created_at: DateTime<Utc>,
}

/// Agent task event pushed via Redis Pub/Sub to notify WebSocket clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentTaskEvent {
    /// Task ID
    pub task_id: i64,
    /// Project this task belongs to.
    pub project_id: Uuid,
    /// Parent task ID (null for root tasks).
    pub parent_id: Option<i64>,
    /// Event type: started | progress | done | failed | child_done
    pub event: String,
    /// Human-readable progress/status text.
    pub message: Option<String>,
    /// Task output (only on done event).
    pub output: Option<String>,
    /// Error message (only on failed event).
    pub error: Option<String>,
    /// Current status.
    pub status: String,
    /// Timestamp.
    pub timestamp: DateTime<Utc>,
}
