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

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct UserInfo {
    pub uid: Uuid,
    pub username: String,
    pub avatar_url: Option<String>,
}

pub const MAX_ROOM_NAME_LEN: usize = 100;
pub const MAX_CATEGORY_NAME_LEN: usize = 100;
pub const MAX_MESSAGE_CONTENT_LEN: usize = 10000;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum RoomEventType {
    RoomCreated,
    RoomDeleted,
    RoomRenamed,
    RoomMoved,
    CategoryCreated,
    CategoryDeleted,
    CategoryUpdated,
    NewMessage,
    MessageEdited,
    MessageRevoked,
    MessagePinned,
    MessageUnpinned,
    MemberJoined,
    MemberRemoved,
    ReadReceipt,
    ReactionAdded,
    ReactionRemoved,
}

impl RoomEventType {
    pub fn as_str(&self) -> &'static str {
        match self {
            RoomEventType::RoomCreated => "room_created",
            RoomEventType::RoomDeleted => "room_deleted",
            RoomEventType::RoomRenamed => "room_renamed",
            RoomEventType::RoomMoved => "room_moved",
            RoomEventType::CategoryCreated => "category_created",
            RoomEventType::CategoryDeleted => "category_deleted",
            RoomEventType::CategoryUpdated => "category_updated",
            RoomEventType::NewMessage => "new_message",
            RoomEventType::MessageEdited => "message_edited",
            RoomEventType::MessageRevoked => "message_revoked",
            RoomEventType::MessagePinned => "message_pinned",
            RoomEventType::MessageUnpinned => "message_unpinned",
            RoomEventType::MemberJoined => "member_joined",
            RoomEventType::MemberRemoved => "member_removed",
            RoomEventType::ReadReceipt => "read_receipt",
            RoomEventType::ReactionAdded => "reaction_added",
            RoomEventType::ReactionRemoved => "reaction_removed",
        }
    }

    pub fn from_str(s: &str) -> Option<Self> {
        match s {
            "room_created" => Some(RoomEventType::RoomCreated),
            "room_deleted" => Some(RoomEventType::RoomDeleted),
            "room_renamed" => Some(RoomEventType::RoomRenamed),
            "room_moved" => Some(RoomEventType::RoomMoved),
            "category_created" => Some(RoomEventType::CategoryCreated),
            "category_deleted" => Some(RoomEventType::CategoryDeleted),
            "category_updated" => Some(RoomEventType::CategoryUpdated),
            "new_message" => Some(RoomEventType::NewMessage),
            "message_edited" => Some(RoomEventType::MessageEdited),
            "message_revoked" => Some(RoomEventType::MessageRevoked),
            "message_pinned" => Some(RoomEventType::MessagePinned),
            "message_unpinned" => Some(RoomEventType::MessageUnpinned),
            "member_joined" => Some(RoomEventType::MemberJoined),
            "member_removed" => Some(RoomEventType::MemberRemoved),
            "read_receipt" => Some(RoomEventType::ReadReceipt),
            "reaction_added" => Some(RoomEventType::ReactionAdded),
            "reaction_removed" => Some(RoomEventType::ReactionRemoved),
            _ => None,
        }
    }
}

impl std::fmt::Display for RoomEventType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomCategoryCreateRequest {
    pub name: String,
    pub position: Option<i32>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomCategoryUpdateRequest {
    pub name: Option<String>,
    pub position: Option<i32>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomCategoryResponse {
    pub id: Uuid,
    pub project: Uuid,
    pub name: String,
    pub position: i32,
    pub created_by: Uuid,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomCreateRequest {
    pub room_name: String,
    #[serde(rename = "room_public")]
    pub public: bool,
    pub category: Option<Uuid>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomUpdateRequest {
    pub room_name: Option<String>,
    #[serde(rename = "room_public")]
    pub public: Option<bool>,
    pub category: Option<Uuid>,
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct RoomResponse {
    pub id: Uuid,
    pub project: Uuid,
    pub room_name: String,
    pub public: bool,
    pub category: Option<Uuid>,
    pub created_by: Uuid,
    pub created_at: DateTime<Utc>,
    pub last_msg_at: DateTime<Utc>,
    #[serde(default)]
    pub unread_count: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMemberAddRequest {
    pub user_id: Uuid,
    pub role: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMemberRoleUpdateRequest {
    pub user_id: Uuid,
    pub role: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMemberReadSeqRequest {
    pub last_read_seq: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct RoomMemberResponse {
    pub room: Uuid,
    pub user: Uuid,
    pub user_info: Option<UserInfo>,
    pub role: String,
    pub first_msg_in: Option<DateTime<Utc>>,
    pub joined_at: Option<DateTime<Utc>>,
    pub last_read_seq: Option<i64>,
    pub do_not_disturb: bool,
    pub dnd_start_hour: Option<i16>,
    pub dnd_end_hour: Option<i16>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMemberUpdateDndRequest {
    pub do_not_disturb: Option<bool>,
    pub dnd_start_hour: Option<i16>,
    pub dnd_end_hour: Option<i16>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMessageCreateRequest {
    pub content: String,
    pub content_type: Option<String>,
    #[serde(rename = "thread_id")]
    pub thread: Option<Uuid>,
    pub in_reply_to: Option<Uuid>,
    #[serde(default)]
    pub attachment_ids: Vec<Uuid>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMessageUpdateRequest {
    pub content: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomMessageSearchRequest {
    pub q: String,
    pub start_time: Option<DateTime<Utc>>,
    pub end_time: Option<DateTime<Utc>>,
    pub sender_id: Option<Uuid>,
    pub content_type: Option<String>,
    pub limit: Option<u64>,
    pub offset: Option<u64>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomMessageResponse {
    pub id: Uuid,
    pub seq: i64,
    pub room: Uuid,
    pub sender_type: String,
    pub sender_id: Option<Uuid>,
    pub display_name: Option<String>,
    pub thread: Option<Uuid>,
    pub in_reply_to: Option<Uuid>,
    pub content: String,
    pub content_type: String,
    pub edited_at: Option<DateTime<Utc>>,
    pub send_at: DateTime<Utc>,
    pub revoked: Option<DateTime<Utc>>,
    pub revoked_by: Option<Uuid>,
    /// Highlighted content with <mark> tags around matched terms (for search results)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub highlighted_content: Option<String>,
    #[serde(default)]
    pub attachment_ids: Vec<Uuid>,
}

/// Search result wrapper (keeps API compatibility)
#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomMessageSearchResult {
    #[serde(flatten)]
    pub message: RoomMessageResponse,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomMessageListResponse {
    pub messages: Vec<RoomMessageResponse>,
    pub total: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomThreadCreateRequest {
    pub parent_seq: i64,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomThreadResponse {
    pub id: Uuid,
    pub room: Uuid,
    pub parent: i64,
    pub created_by: Uuid,
    pub participants: serde_json::Value,
    pub last_message_at: DateTime<Utc>,
    pub last_message_preview: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomPinResponse {
    pub room: Uuid,
    pub message: Uuid,
    pub pinned_by: Uuid,
    pub pinned_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct RoomAiUpsertRequest {
    pub model: Uuid,
    pub version: Option<Uuid>,
    pub history_limit: Option<i64>,
    pub system_prompt: Option<String>,
    pub temperature: Option<f64>,
    pub max_tokens: Option<i64>,
    pub use_exact: Option<bool>,
    pub think: Option<bool>,
    pub stream: Option<bool>,
    pub min_score: Option<f32>,
    pub agent_type: Option<String>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct RoomAiResponse {
    pub room: Uuid,
    pub model: Uuid,
    pub model_name: Option<String>,
    pub version: Option<Uuid>,
    pub call_count: i64,
    pub last_call_at: Option<DateTime<Utc>>,
    pub history_limit: Option<i64>,
    pub system_prompt: Option<String>,
    pub temperature: Option<f64>,
    pub max_tokens: Option<i64>,
    pub use_exact: bool,
    pub think: bool,
    pub stream: bool,
    pub min_score: Option<f32>,
    pub agent_type: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum NotificationType {
    Mention,
    Invitation,
    RoleChange,
    RoomCreated,
    RoomDeleted,
    SystemAnnouncement,
    ProjectInvitation,
    WorkspaceInvitation,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct NotificationCreateRequest {
    pub notification_type: NotificationType,
    pub user_id: Uuid,
    pub title: String,
    pub content: Option<String>,
    pub room_id: Option<Uuid>,
    pub project_id: Uuid,
    pub related_message_id: Option<Uuid>,
    pub related_user_id: Option<Uuid>,
    pub related_room_id: Option<Uuid>,
    pub metadata: Option<serde_json::Value>,
    pub expires_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct NotificationResponse {
    pub id: Uuid,
    pub room: Option<Uuid>,
    pub project: Option<Uuid>,
    pub user_id: Option<Uuid>,
    pub user_info: Option<UserInfo>,
    pub notification_type: String,
    pub title: String,
    pub content: Option<String>,
    pub related_message_id: Option<Uuid>,
    pub related_user_id: Option<Uuid>,
    pub related_room_id: Option<Uuid>,
    pub metadata: serde_json::Value,
    pub is_read: bool,
    pub is_archived: bool,
    pub created_at: DateTime<Utc>,
    pub read_at: Option<DateTime<Utc>>,
    pub expires_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct NotificationListResponse {
    pub notifications: Vec<NotificationResponse>,
    pub total: i64,
    pub unread_count: i64,
}

#[derive(Debug, Clone, Serialize, utoipa::ToSchema)]
pub struct NotificationEvent {
    pub event_type: String,
    pub notification: NotificationResponse,
    pub timestamp: DateTime<Utc>,
}

impl NotificationEvent {
    pub fn new(notification: NotificationResponse) -> Self {
        Self {
            event_type: "notification_created".into(),
            notification,
            timestamp: Utc::now(),
        }
    }
}
