use super::{ DeletedMessages, EditedMessage, FakeTdClient, ForwardedMessages, SearchQuery, SentMessage, TdUpdate, }; use tele_tui::tdlib::types::ReactionInfo; use tele_tui::tdlib::{ChatInfo, MessageInfo, ProfileInfo, ReplyInfo}; use tele_tui::types::{ChatId, MessageId, UserId}; #[allow(dead_code)] impl FakeTdClient { pub async fn load_chats(&self, limit: usize) -> Result, String> { if self.should_fail() { return Err("Failed to load chats".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; } let chats = self .chats .lock() .unwrap() .iter() .take(limit) .cloned() .collect(); Ok(chats) } pub async fn open_chat(&self, chat_id: ChatId) -> Result<(), String> { if self.should_fail() { return Err("Failed to open chat".to_string()); } *self.current_chat_id.lock().unwrap() = Some(chat_id.as_i64()); Ok(()) } pub async fn get_chat_history( &self, chat_id: ChatId, limit: i32, ) -> Result, String> { if self.should_fail() { return Err("Failed to load history".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; } let messages = self .messages .lock() .unwrap() .get(&chat_id.as_i64()) .map(|msgs| msgs.iter().take(limit as usize).cloned().collect()) .unwrap_or_default(); Ok(messages) } pub async fn load_older_messages( &self, chat_id: ChatId, from_message_id: MessageId, ) -> Result, String> { if self.should_fail() { return Err("Failed to load older messages".to_string()); } let messages = self.messages.lock().unwrap(); let chat_messages = messages.get(&chat_id.as_i64()).ok_or("Chat not found")?; if let Some(idx) = chat_messages.iter().position(|m| m.id() == from_message_id) { let older = chat_messages.iter().take(idx).cloned().collect(); Ok(older) } else { Ok(vec![]) } } pub async fn send_message( &self, chat_id: ChatId, text: String, reply_to: Option, reply_info: Option, ) -> Result { if self.should_fail() { return Err("Failed to send message".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; } let message_id = MessageId::new((self.sent_messages.lock().unwrap().len() as i64) + 1000); self.sent_messages.lock().unwrap().push(SentMessage { chat_id: chat_id.as_i64(), text: text.clone(), reply_to, reply_info: reply_info.clone(), }); let message = MessageInfo::new( message_id, "You".to_string(), true, text, vec![], chrono::Utc::now().timestamp() as i32, 0, false, true, true, true, reply_info, None, vec![], ); self.messages .lock() .unwrap() .entry(chat_id.as_i64()) .or_default() .push(message.clone()); self.send_update(TdUpdate::NewMessage { chat_id, message: Box::new(message.clone()) }); Ok(message) } pub async fn edit_message( &self, chat_id: ChatId, message_id: MessageId, new_text: String, ) -> Result { if self.should_fail() { return Err("Failed to edit message".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(150)).await; } self.edited_messages.lock().unwrap().push(EditedMessage { chat_id: chat_id.as_i64(), message_id, new_text: new_text.clone(), }); let mut messages = self.messages.lock().unwrap(); if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) { if let Some(msg) = chat_msgs.iter_mut().find(|m| m.id() == message_id) { msg.content.text = new_text.clone(); msg.metadata.edit_date = msg.metadata.date + 60; let updated = msg.clone(); drop(messages); self.send_update(TdUpdate::MessageContent { chat_id, message_id, new_text }); return Ok(updated); } } Err("Message not found".to_string()) } pub async fn delete_messages( &self, chat_id: ChatId, message_ids: Vec, revoke: bool, ) -> Result<(), String> { if self.should_fail() { return Err("Failed to delete messages".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; } self.deleted_messages.lock().unwrap().push(DeletedMessages { chat_id: chat_id.as_i64(), message_ids: message_ids.clone(), revoke, }); let mut messages = self.messages.lock().unwrap(); if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) { chat_msgs.retain(|m| !message_ids.contains(&m.id())); } drop(messages); self.send_update(TdUpdate::DeleteMessages { chat_id, message_ids }); Ok(()) } pub async fn forward_messages( &self, to_chat_id: ChatId, from_chat_id: ChatId, message_ids: Vec, ) -> Result<(), String> { if self.should_fail() { return Err("Failed to forward messages".to_string()); } if self.simulate_delays { tokio::time::sleep(tokio::time::Duration::from_millis(150)).await; } self.forwarded_messages .lock() .unwrap() .push(ForwardedMessages { from_chat_id: from_chat_id.as_i64(), to_chat_id: to_chat_id.as_i64(), message_ids, }); Ok(()) } pub async fn search_messages( &self, chat_id: ChatId, query: &str, ) -> Result, String> { if self.should_fail() { return Err("Failed to search messages".to_string()); } let messages = self.messages.lock().unwrap(); let results: Vec<_> = messages .get(&chat_id.as_i64()) .map(|msgs| { msgs.iter() .filter(|m| m.text().to_lowercase().contains(&query.to_lowercase())) .cloned() .collect() }) .unwrap_or_default(); self.searched_queries.lock().unwrap().push(SearchQuery { chat_id: chat_id.as_i64(), query: query.to_string(), results_count: results.len(), }); Ok(results) } pub async fn set_draft_message(&self, chat_id: ChatId, text: String) -> Result<(), String> { if text.is_empty() { self.drafts.lock().unwrap().remove(&chat_id.as_i64()); } else { self.drafts .lock() .unwrap() .insert(chat_id.as_i64(), text.clone()); } self.send_update(TdUpdate::ChatDraftMessage { chat_id, draft_text: if text.is_empty() { None } else { Some(text) }, }); Ok(()) } pub async fn send_chat_action(&self, chat_id: ChatId, action: String) { self.chat_actions .lock() .unwrap() .push((chat_id.as_i64(), action.clone())); if action == "Typing" { *self.typing_chat_id.lock().unwrap() = Some(chat_id.as_i64()); } else if action == "Cancel" { *self.typing_chat_id.lock().unwrap() = None; } } pub async fn get_message_available_reactions( &self, _chat_id: ChatId, _message_id: MessageId, ) -> Result, String> { if self.should_fail() { return Err("Failed to get available reactions".to_string()); } Ok(self.available_reactions.lock().unwrap().clone()) } pub async fn toggle_reaction( &self, chat_id: ChatId, message_id: MessageId, emoji: String, ) -> Result<(), String> { if self.should_fail() { return Err("Failed to toggle reaction".to_string()); } let mut messages = self.messages.lock().unwrap(); if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) { if let Some(msg) = chat_msgs.iter_mut().find(|m| m.id() == message_id) { let reactions = &mut msg.interactions.reactions; if let Some(pos) = reactions .iter() .position(|reaction| reaction.emoji == emoji && reaction.is_chosen) { reactions.remove(pos); } else if let Some(reaction) = reactions .iter_mut() .find(|reaction| reaction.emoji == emoji) { reaction.is_chosen = true; reaction.count += 1; } else { reactions.push(ReactionInfo { emoji: emoji.clone(), count: 1, is_chosen: true, }); } let updated_reactions = reactions.clone(); drop(messages); self.send_update(TdUpdate::MessageInteractionInfo { chat_id, message_id, reactions: updated_reactions, }); } } Ok(()) } pub async fn download_file(&self, file_id: i32) -> Result { if self.should_fail() { return Err("Failed to download file".to_string()); } self.downloaded_files .lock() .unwrap() .get(&file_id) .cloned() .ok_or_else(|| format!("File {} not found", file_id)) } pub async fn get_profile_info(&self, chat_id: ChatId) -> Result { if self.should_fail() { return Err("Failed to get profile info".to_string()); } self.profiles .lock() .unwrap() .get(&chat_id.as_i64()) .cloned() .ok_or_else(|| "Profile not found".to_string()) } pub async fn view_messages(&self, chat_id: ChatId, message_ids: Vec) { self.viewed_messages .lock() .unwrap() .push((chat_id.as_i64(), message_ids.iter().map(|id| id.as_i64()).collect())); } pub async fn load_folder_chats(&self, _folder_id: i32, _limit: usize) -> Result<(), String> { if self.should_fail() { return Err("Failed to load folder chats".to_string()); } Ok(()) } fn send_update(&self, update: TdUpdate) { if let Some(tx) = self.update_tx.lock().unwrap().as_ref() { let _ = tx.send(update); } } fn should_fail(&self) -> bool { let mut fail = self.fail_next_operation.lock().unwrap(); if *fail { *fail = false; true } else { false } } pub fn fail_next(&self) { *self.fail_next_operation.lock().unwrap() = true; } pub fn simulate_incoming_message(&self, chat_id: ChatId, text: String, sender_name: &str) { let message_id = MessageId::new(9000 + chrono::Utc::now().timestamp()); let message = MessageInfo::new( message_id, sender_name.to_string(), false, text, vec![], chrono::Utc::now().timestamp() as i32, 0, false, false, false, true, None, None, vec![], ); self.messages .lock() .unwrap() .entry(chat_id.as_i64()) .or_default() .push(message.clone()); self.send_update(TdUpdate::NewMessage { chat_id, message: Box::new(message) }); } pub fn simulate_typing(&self, chat_id: ChatId, user_id: UserId) { self.send_update(TdUpdate::ChatAction { chat_id, user_id, action: "Typing".to_string() }); } pub fn simulate_network_change(&self, state: tele_tui::tdlib::NetworkState) { *self.network_state.lock().unwrap() = state.clone(); self.send_update(TdUpdate::ConnectionState { state }); } pub fn simulate_read_outbox(&self, chat_id: ChatId, last_read_message_id: MessageId) { self.send_update(TdUpdate::ChatReadOutbox { chat_id, last_read_outbox_message_id: last_read_message_id, }); } }