use crate::platform;
use anyhow::Result;
use std::sync::mpsc;
use std::time::Duration;

#[derive(Clone, Debug)]
pub struct ConversationSummary {
    pub id: String,
    pub title: String,
    pub preview: String,
    pub participants: Vec<String>,
    pub unread_count: u32,
    pub date_unix: i64,
}

#[derive(Clone, Debug)]
pub struct ChatMessage {
    pub id: String,
    pub sender: String,
    pub text: String,
    pub date_unix: i64,
    pub attachments: Vec<Attachment>,
}

impl ChatMessage {
    pub fn from_me(&self) -> bool {
        self.sender == "(Me)"
    }
}

#[derive(Clone, Debug, Default)]
pub struct AttributionInfo {
    pub width: Option<u32>,
    pub height: Option<u32>,
}

#[derive(Clone, Debug, Default)]
pub struct AttachmentMetadata {
    pub attribution_info: Option<AttributionInfo>,
}

#[derive(Clone, Debug, Default)]
pub struct Attachment {
    pub guid: String,
    pub downloaded: bool,
    pub preview_downloaded: bool,
    pub metadata: Option<AttachmentMetadata>,
}

#[derive(Clone, Debug, Default)]
pub struct AttachmentInfo {
    pub path: String,
    pub preview_path: String,
    pub downloaded: bool,
    pub preview_downloaded: bool,
}

#[derive(Clone, Debug, Default)]
pub struct SettingsSnapshot {
    pub server_url: String,
    pub username: String,
    pub password: String,
}

pub enum Request {
    RefreshConversations,
    RefreshMessages {
        conversation_id: String,
    },
    SendMessage {
        conversation_id: String,
        text: String,
    },
    SendMessageWithAttachments {
        conversation_id: String,
        text: String,
        attachment_guids: Vec<String>,
    },
    MarkRead {
        conversation_id: String,
    },
    SyncConversation {
        conversation_id: String,
    },
    SyncConversationList,
    SyncAllConversations,
    DownloadAttachment {
        attachment_guid: String,
        preview: bool,
    },
    GetAttachmentInfo {
        attachment_guid: String,
    },
    UploadAttachment {
        path: String,
    },
    LoadSettings,
    SaveSettings {
        server_url: String,
        username: String,
        password: String,
    },
}

pub enum Event {
    Conversations(Vec<ConversationSummary>),
    Messages {
        conversation_id: String,
        messages: Vec<ChatMessage>,
    },
    MessageSent {
        conversation_id: String,
        outgoing_id: Option<String>,
    },
    MarkedRead,
    ConversationSyncTriggered {
        conversation_id: String,
    },
    ConversationListSyncTriggered,
    AllConversationsSyncTriggered,
    AttachmentDownloadQueued {
        attachment_guid: String,
        preview: bool,
    },
    AttachmentDownloaded {
        attachment_guid: String,
    },
    AttachmentDownloadFailed {
        attachment_guid: String,
        error: String,
    },
    AttachmentUploaded {
        upload_guid: String,
        attachment_guid: String,
    },
    AttachmentUploadQueued {
        upload_guid: String,
        path: String,
    },
    AttachmentInfo {
        attachment_guid: String,
        info: AttachmentInfo,
    },
    SettingsLoaded(SettingsSnapshot),
    SettingsSaved,
    ConversationsUpdated,
    MessagesUpdated {
        conversation_id: String,
    },
    UpdateStreamReconnected,
    Error(String),
}

pub fn spawn_worker(
    request_rx: std::sync::mpsc::Receiver<Request>,
    event_tx: std::sync::mpsc::Sender<Event>,
) -> std::thread::JoinHandle<()> {
    std::thread::spawn(move || {
        let mut client = match platform::new_daemon_client() {
            Ok(c) => c,
            Err(e) => {
                let _ = event_tx.send(Event::Error(format!("Failed to connect to daemon: {e}")));
                return;
            }
        };

        if let Err(e) = client.install_signal_handlers(event_tx.clone()) {
            let _ = event_tx.send(Event::Error(format!(
                "Failed to install daemon signals: {e}"
            )));
        }

        loop {
            match request_rx.recv_timeout(Duration::from_millis(100)) {
                Ok(req) => {
                    let res = match req {
                        Request::RefreshConversations => {
                            client.get_conversations(200, 0).map(Event::Conversations)
                        }
                        Request::RefreshMessages { conversation_id } => client
                            .get_messages(conversation_id.clone(), None)
                            .map(|messages| Event::Messages {
                                conversation_id,
                                messages,
                            }),
                        Request::SendMessage {
                            conversation_id,
                            text,
                        } => {
                            client
                                .send_message(conversation_id.clone(), text)
                                .map(|outgoing_id| Event::MessageSent {
                                    conversation_id,
                                    outgoing_id,
                                })
                        }
                        Request::SendMessageWithAttachments {
                            conversation_id,
                            text,
                            attachment_guids,
                        } => client
                            .send_message_with_attachments(
                                conversation_id.clone(),
                                text,
                                attachment_guids,
                            )
                            .map(|outgoing_id| Event::MessageSent {
                                conversation_id,
                                outgoing_id,
                            }),
                        Request::MarkRead { conversation_id } => client
                            .mark_conversation_as_read(conversation_id.clone())
                            .map(|_| Event::MarkedRead),
                        Request::SyncConversation { conversation_id } => client
                            .sync_conversation(conversation_id.clone())
                            .map(|_| Event::ConversationSyncTriggered { conversation_id }),
                        Request::SyncConversationList => client
                            .sync_conversation_list()
                            .map(|_| Event::ConversationListSyncTriggered),
                        Request::SyncAllConversations => client
                            .sync_all_conversations()
                            .map(|_| Event::AllConversationsSyncTriggered),
                        Request::DownloadAttachment {
                            attachment_guid,
                            preview,
                        } => client
                            .download_attachment(attachment_guid.clone(), preview)
                            .map(|_| Event::AttachmentDownloadQueued {
                                attachment_guid,
                                preview,
                            }),
                        Request::GetAttachmentInfo { attachment_guid } => client
                            .get_attachment_info(attachment_guid.clone())
                            .map(|info| Event::AttachmentInfo {
                                attachment_guid,
                                info,
                            }),
                        Request::UploadAttachment { path } => client
                            .upload_attachment(path.clone())
                            .map(|upload_guid| Event::AttachmentUploadQueued { upload_guid, path }),
                        Request::LoadSettings => client.get_settings().map(Event::SettingsLoaded),
                        Request::SaveSettings {
                            server_url,
                            username,
                            password,
                        } => client
                            .save_settings(server_url, username, password)
                            .map(|_| Event::SettingsSaved),
                    };

                    match res {
                        Ok(evt) => {
                            let _ = event_tx.send(evt);
                        }
                        Err(e) => {
                            let _ = event_tx.send(Event::Error(format!("{e}")));
                        }
                    }
                }
                Err(mpsc::RecvTimeoutError::Timeout) => {}
                Err(mpsc::RecvTimeoutError::Disconnected) => break,
            }

            if let Err(e) = client.poll(Duration::from_millis(0)) {
                let _ = event_tx.send(Event::Error(format!("Daemon polling error: {e}")));
            }
        }
    })
}

pub(crate) trait DaemonClient {
    fn get_conversations(&mut self, limit: i32, offset: i32) -> Result<Vec<ConversationSummary>>;
    fn get_messages(
        &mut self,
        conversation_id: String,
        last_message_id: Option<String>,
    ) -> Result<Vec<ChatMessage>>;
    fn send_message(&mut self, conversation_id: String, text: String) -> Result<Option<String>>;
    fn send_message_with_attachments(
        &mut self,
        conversation_id: String,
        text: String,
        attachment_guids: Vec<String>,
    ) -> Result<Option<String>> {
        let _ = attachment_guids;
        self.send_message(conversation_id, text)
    }
    fn mark_conversation_as_read(&mut self, conversation_id: String) -> Result<()>;
    fn sync_conversation(&mut self, conversation_id: String) -> Result<()>;
    fn sync_conversation_list(&mut self) -> Result<()> {
        Ok(())
    }
    fn sync_all_conversations(&mut self) -> Result<()> {
        Ok(())
    }
    fn download_attachment(&mut self, _attachment_guid: String, _preview: bool) -> Result<()> {
        anyhow::bail!("Attachment downloads are not supported on this platform")
    }
    fn get_attachment_info(&mut self, _attachment_guid: String) -> Result<AttachmentInfo> {
        anyhow::bail!("Attachment info is not supported on this platform")
    }
    fn upload_attachment(&mut self, _path: String) -> Result<String> {
        anyhow::bail!("Attachment uploads are not supported on this platform")
    }
    fn get_settings(&mut self) -> Result<SettingsSnapshot> {
        anyhow::bail!("Settings are not supported on this platform")
    }
    fn save_settings(
        &mut self,
        _server_url: String,
        _username: String,
        _password: String,
    ) -> Result<()> {
        anyhow::bail!("Settings are not supported on this platform")
    }
    fn install_signal_handlers(&mut self, _event_tx: mpsc::Sender<Event>) -> Result<()> {
        Ok(())
    }
    fn poll(&mut self, timeout: Duration) -> Result<()> {
        std::thread::sleep(timeout);
        Ok(())
    }
}
