//! Command DTOs for mutating and querying chat state via HTTP [`openapi.yaml`](../../../../openapi.yaml) `/chat/*`.

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

use crate::ids::{MessageId, RoomId, UserId};

/// Input for `POST /chat/rooms`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateRoom {
    /// Room kind discriminator (for example `direct`, `group`, `channel`).
    pub kind: String,
    pub title: Option<String>,
    #[serde(default)]
    pub member_user_ids: Vec<UserId>,
}

/// Input for `PATCH /chat/rooms/{room_id}`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateRoom {
    pub room_id: RoomId,
    pub title: Option<String>,
}

/// Input for `POST /chat/rooms/{room_id}/archive`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArchiveRoom {
    pub room_id: RoomId,
}

/// Input for `GET /chat/rooms` query parameters.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListRooms {
    pub limit: Option<i64>,
    pub offset: Option<i64>,
    pub include_archived: Option<bool>,
}

/// Input for `GET /chat/rooms/{room_id}/messages` query parameters.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListMessages {
    pub room_id: RoomId,
    pub limit: Option<i64>,
    /// Cursor: return messages with `room_seq` strictly less than this value.
    pub before_seq: Option<i64>,
    /// Cursor: return messages with `room_seq` strictly greater than this value.
    pub after_seq: Option<i64>,
}

/// File attachment reference when sending a message.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttachmentInput {
    pub file_id: String,
    /// Display order within the message body.
    pub ordinal: i32,
}

/// Input for `POST /chat/rooms/{room_id}/messages`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendMessage {
    pub room_id: RoomId,
    /// Client-supplied idempotency key for deduplication.
    pub client_message_id: Option<String>,
    pub body_text: Option<String>,
    pub body_json: Option<Value>,
    pub reply_to_message_id: Option<MessageId>,
    pub metadata_json: Option<Value>,
    #[serde(default)]
    pub attachments: Vec<AttachmentInput>,
}

/// Input for `PATCH /chat/rooms/{room_id}/messages/{message_id}`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EditMessage {
    pub room_id: RoomId,
    pub message_id: MessageId,
    pub body_text: Option<String>,
    pub body_json: Option<Value>,
    pub metadata_json: Option<Value>,
}

/// Input for `DELETE /chat/rooms/{room_id}/messages/{message_id}`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteMessage {
    pub room_id: RoomId,
    pub message_id: MessageId,
}

/// Input for `POST /chat/rooms/{room_id}/read-cursor` and WSS `chat.read.up_to`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarkReadUpTo {
    pub room_id: RoomId,
    pub message_id: Option<MessageId>,
    /// Preferred when both `message_id` and `seq` are supplied.
    pub seq: Option<i64>,
}

/// Input for `POST /chat/messages/{message_id}/reactions`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddReaction {
    pub message_id: MessageId,
    pub emoji: String,
}

/// Input for `DELETE /chat/messages/{message_id}/reactions/{emoji}`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoveReaction {
    pub message_id: MessageId,
    pub emoji: String,
}

/// Input for `POST /chat/rooms/{room_id}/members`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddMembers {
    pub room_id: RoomId,
    pub user_ids: Vec<UserId>,
    pub role: Option<String>,
}

/// Input for `DELETE /chat/rooms/{room_id}/members/{user_id}`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoveMember {
    pub room_id: RoomId,
    pub user_id: UserId,
}

/// Input for `POST /chat/messages/search`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchMessages {
    pub query: String,
    pub room_id: Option<RoomId>,
    pub limit: Option<i64>,
}
