1use crate::identity::enhanced::{EnhancedIdentity, OrganizationId};
24use crate::storage::{StorageManager, keys, ttl};
25use crate::quantum_crypto::types::GroupId;
27use serde::{Deserialize, Serialize};
28use std::collections::HashMap;
29use std::time::SystemTime;
30use thiserror::Error;
31use uuid::Uuid;
32
33#[derive(Debug, Error)]
35pub enum ChatError {
36 #[error("Storage error: {0}")]
37 StorageError(#[from] crate::storage::StorageError),
38
39 #[error("Channel not found: {0}")]
40 ChannelNotFound(String),
41
42 #[error("Permission denied: {0}")]
43 PermissionDenied(String),
44
45 #[error("Invalid operation: {0}")]
46 InvalidOperation(String),
47}
48
49type Result<T> = std::result::Result<T, ChatError>;
50
51#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub struct ChannelId(pub String);
54
55impl Default for ChannelId {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl ChannelId {
62 pub fn new() -> Self {
64 Self(Uuid::new_v4().to_string())
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
70pub struct MessageId(pub String);
71
72impl Default for MessageId {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl MessageId {
79 pub fn new() -> Self {
81 Self(Uuid::new_v4().to_string())
82 }
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
87pub struct ThreadId(pub String);
88
89pub type UserId = String;
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub enum ChannelType {
95 Public,
97
98 Private {
100 access_group: GroupId,
101 visibility: ChannelVisibility,
102 },
103
104 Direct { participants: Vec<UserId> },
106
107 GroupDirect {
109 participants: Vec<UserId>,
110 name: Option<String>,
111 },
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub enum ChannelVisibility {
117 Listed,
119
120 Hidden,
122
123 Secret,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct Channel {
130 pub id: ChannelId,
131 pub name: String,
132 pub description: String,
133 pub channel_type: ChannelType,
134 pub organization_id: Option<OrganizationId>,
135 pub created_by: UserId,
136 pub created_at: SystemTime,
137 pub members: Vec<ChannelMember>,
138 pub settings: ChannelSettings,
139 pub metadata: HashMap<String, String>,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct ChannelMember {
145 pub user_id: UserId,
146 pub role: ChannelRole,
147 pub joined_at: SystemTime,
148 pub last_read: Option<MessageId>,
149 pub notifications: NotificationSettings,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
154pub enum ChannelRole {
155 Owner,
156 Admin,
157 Moderator,
158 Member,
159 Guest,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct NotificationSettings {
165 pub all_messages: bool,
166 pub mentions_only: bool,
167 pub muted: bool,
168 pub muted_until: Option<SystemTime>,
169}
170
171impl Default for NotificationSettings {
172 fn default() -> Self {
173 Self {
174 all_messages: true,
175 mentions_only: false,
176 muted: false,
177 muted_until: None,
178 }
179 }
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct ChannelSettings {
185 pub allow_threads: bool,
186 pub allow_reactions: bool,
187 pub allow_files: bool,
188 pub allow_voice_video: bool,
189 pub message_retention_days: Option<u32>,
190 pub max_message_length: usize,
191 pub slow_mode_seconds: Option<u32>,
192}
193
194impl Default for ChannelSettings {
195 fn default() -> Self {
196 Self {
197 allow_threads: true,
198 allow_reactions: true,
199 allow_files: true,
200 allow_voice_video: true,
201 message_retention_days: Some(90),
202 max_message_length: 4000,
203 slow_mode_seconds: None,
204 }
205 }
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct Message {
211 pub id: MessageId,
212 pub channel_id: ChannelId,
213 pub thread_id: Option<ThreadId>,
214 pub author: UserId,
215 pub content: MessageContent,
216 pub created_at: SystemTime,
217 pub edited_at: Option<SystemTime>,
218 pub deleted_at: Option<SystemTime>,
219 pub reactions: Vec<Reaction>,
220 pub mentions: Vec<Mention>,
221 pub attachments: Vec<Attachment>,
222 pub reply_to: Option<MessageId>,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub enum MessageContent {
228 Text(String),
230
231 RichText {
233 text: String,
234 formatting: Vec<TextFormat>,
235 },
236
237 System(SystemMessage),
239
240 Encrypted {
242 ciphertext: Vec<u8>,
243 algorithm: String,
244 },
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct TextFormat {
250 pub start: usize,
251 pub end: usize,
252 pub format_type: FormatType,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
257pub enum FormatType {
258 Bold,
259 Italic,
260 Code,
261 Strike,
262 Link(String),
263 Mention(UserId),
264 ChannelRef(ChannelId),
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
269pub enum SystemMessage {
270 UserJoined(UserId),
271 UserLeft(UserId),
272 UserInvited {
273 inviter: UserId,
274 invitee: UserId,
275 },
276 ChannelRenamed {
277 old_name: String,
278 new_name: String,
279 },
280 ChannelDescriptionChanged,
281 CallStarted {
282 call_id: String,
283 },
284 CallEnded {
285 call_id: String,
286 duration_seconds: u64,
287 },
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct Reaction {
293 pub emoji: String,
294 pub users: Vec<UserId>,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub enum Mention {
300 User(UserId),
301 Channel,
302 Here,
303 Everyone,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct Attachment {
309 pub id: String,
310 pub name: String,
311 pub mime_type: String,
312 pub size: u64,
313 pub url: String,
314 pub thumbnail_url: Option<String>,
315 pub metadata: AttachmentMetadata,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub enum AttachmentMetadata {
321 Image {
322 width: u32,
323 height: u32,
324 },
325 Video {
326 duration_seconds: u64,
327 width: u32,
328 height: u32,
329 },
330 Audio {
331 duration_seconds: u64,
332 },
333 Document {
334 page_count: Option<u32>,
335 },
336 Other,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
341pub struct Thread {
342 pub id: ThreadId,
343 pub channel_id: ChannelId,
344 pub parent_message_id: MessageId,
345 pub reply_count: u32,
346 pub participant_count: u32,
347 pub last_reply_at: Option<SystemTime>,
348 pub participants: Vec<UserId>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct Call {
354 pub id: String,
355 pub channel_id: ChannelId,
356 pub call_type: CallType,
357 pub started_by: UserId,
358 pub started_at: SystemTime,
359 pub ended_at: Option<SystemTime>,
360 pub participants: Vec<CallParticipant>,
361 pub recording_url: Option<String>,
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
366pub enum CallType {
367 Voice,
368 Video,
369 ScreenShare,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct CallParticipant {
375 pub user_id: UserId,
376 pub joined_at: SystemTime,
377 pub left_at: Option<SystemTime>,
378 pub is_muted: bool,
379 pub is_video_on: bool,
380 pub is_screen_sharing: bool,
381}
382
383pub struct ChatManager {
385 storage: StorageManager,
386 identity: EnhancedIdentity,
387}
388
389impl ChatManager {
390 pub fn new(storage: StorageManager, identity: EnhancedIdentity) -> Self {
392 Self { storage, identity }
393 }
394
395 pub async fn add_member(
397 &mut self,
398 channel_id: &ChannelId,
399 user_id: UserId,
400 role: ChannelRole,
401 ) -> Result<()> {
402 let mut ch = self.get_channel(channel_id).await?;
403 if !ch.members.iter().any(|m| m.user_id == user_id) {
404 ch.members.push(ChannelMember {
405 user_id: user_id.clone(),
406 role,
407 joined_at: SystemTime::now(),
408 last_read: None,
409 notifications: NotificationSettings::default(),
410 });
411 let key = keys::chat_channel(&ch.id.0);
413 self.storage
414 .store_encrypted(&key, &ch, ttl::PROFILE, None)
415 .await?;
416 }
417 Ok(())
418 }
419
420 pub async fn create_channel(
422 &mut self,
423 name: String,
424 description: String,
425 channel_type: ChannelType,
426 organization_id: Option<OrganizationId>,
427 ) -> Result<Channel> {
428 if let Some(_org_id) = &organization_id {
430 }
433
434 let channel = Channel {
435 id: ChannelId::new(),
436 name,
437 description,
438 channel_type,
439 organization_id,
440 created_by: self.identity.base_identity.user_id.clone(),
441 created_at: SystemTime::now(),
442 members: vec![ChannelMember {
443 user_id: self.identity.base_identity.user_id.clone(),
444 role: ChannelRole::Owner,
445 joined_at: SystemTime::now(),
446 last_read: None,
447 notifications: NotificationSettings::default(),
448 }],
449 settings: ChannelSettings::default(),
450 metadata: HashMap::new(),
451 };
452
453 let key = keys::chat_channel(&channel.id.0);
455 self.storage
456 .store_encrypted(&key, &channel, ttl::PROFILE, None)
457 .await?;
458
459 self.add_user_channel(&channel.id).await?;
461
462 if matches!(channel.channel_type, ChannelType::Public) {
464 self.add_public_channel(&channel.id, &channel.name).await?;
465 }
466
467 Ok(channel)
468 }
469
470 pub async fn send_message(
472 &mut self,
473 channel_id: &ChannelId,
474 content: MessageContent,
475 thread_id: Option<ThreadId>,
476 attachments: Vec<Attachment>,
477 ) -> Result<Message> {
478 let channel = self.get_channel(channel_id).await?;
480 if !channel
481 .members
482 .iter()
483 .any(|m| m.user_id == self.identity.base_identity.user_id)
484 {
485 return Err(ChatError::PermissionDenied(
486 "Not a member of channel".to_string(),
487 ));
488 }
489
490 let message = Message {
491 id: MessageId::new(),
492 channel_id: channel_id.clone(),
493 thread_id,
494 author: self.identity.base_identity.user_id.clone(),
495 content,
496 created_at: SystemTime::now(),
497 edited_at: None,
498 deleted_at: None,
499 reactions: vec![],
500 mentions: vec![], attachments,
502 reply_to: None,
503 };
504
505 let msg_key = keys::chat_message(&channel_id.0, &message.id.0);
507 self.storage
508 .store_encrypted(&msg_key, &message, ttl::MESSAGE, None)
509 .await?;
510
511 let timestamp = message
513 .created_at
514 .duration_since(SystemTime::UNIX_EPOCH)
515 .map_err(|e| ChatError::InvalidOperation(format!("Invalid message timestamp: {}", e)))?
516 .as_secs();
517 let index_key = keys::chat_index(&channel_id.0, timestamp);
518 self.storage
519 .store_encrypted(&index_key, &message.id, ttl::MESSAGE, None)
520 .await?;
521
522 Ok(message)
523 }
524
525 pub async fn get_channel(&self, channel_id: &ChannelId) -> Result<Channel> {
527 let key = keys::chat_channel(&channel_id.0);
528 self.storage
529 .get_encrypted(&key)
530 .await
531 .map_err(|_| ChatError::ChannelNotFound(channel_id.0.clone()))
532 }
533
534 pub async fn get_user_channels(&self) -> Result<Vec<ChannelId>> {
536 let key = keys::user_channels(&self.identity.base_identity.user_id);
537 Ok(self
538 .storage
539 .get_encrypted(&key)
540 .await
541 .unwrap_or_else(|_| vec![]))
542 }
543
544 async fn add_user_channel(&mut self, channel_id: &ChannelId) -> Result<()> {
546 let mut channels = self.get_user_channels().await.unwrap_or_default();
547 if !channels.contains(channel_id) {
548 channels.push(channel_id.clone());
549
550 let key = keys::user_channels(&self.identity.base_identity.user_id);
551 self.storage
552 .store_encrypted(&key, &channels, ttl::PROFILE, None)
553 .await?;
554 }
555 Ok(())
556 }
557
558 async fn add_public_channel(&mut self, channel_id: &ChannelId, name: &str) -> Result<()> {
560 let key = keys::public_channel_list();
561 let mut public_channels: HashMap<String, String> =
562 self.storage.get_public(&key).await.unwrap_or_default();
563
564 public_channels.insert(channel_id.0.clone(), name.to_string());
565
566 self.storage
567 .store_public(&key, &public_channels, ttl::PROFILE)
568 .await?;
569
570 Ok(())
571 }
572
573 pub async fn create_thread(
575 &mut self,
576 channel_id: &ChannelId,
577 parent_message_id: &MessageId,
578 ) -> Result<Thread> {
579 let thread = Thread {
580 id: ThreadId(Uuid::new_v4().to_string()),
581 channel_id: channel_id.clone(),
582 parent_message_id: parent_message_id.clone(),
583 reply_count: 0,
584 participant_count: 1,
585 last_reply_at: None,
586 participants: vec![self.identity.base_identity.user_id.clone()],
587 };
588
589 Ok(thread)
591 }
592
593 pub async fn add_reaction(
595 &mut self,
596 channel_id: &ChannelId,
597 message_id: &MessageId,
598 emoji: String,
599 ) -> Result<()> {
600 let msg_key = keys::chat_message(&channel_id.0, &message_id.0);
601 let mut message: Message = self.storage.get_encrypted(&msg_key).await?;
602
603 let user_id = &self.identity.base_identity.user_id;
605 if let Some(reaction) = message.reactions.iter_mut().find(|r| r.emoji == emoji) {
606 if !reaction.users.contains(user_id) {
607 reaction.users.push(user_id.clone());
608 }
609 } else {
610 message.reactions.push(Reaction {
611 emoji,
612 users: vec![user_id.clone()],
613 });
614 }
615
616 self.storage
618 .store_encrypted(&msg_key, &message, ttl::MESSAGE, None)
619 .await?;
620
621 Ok(())
622 }
623}