/// Unified session identifier composed of channel, chat_id, and dialog_id
///
/// Format: `channel:chat_id:dialog_id`
///
/// Examples:
/// - CLI: `"cli_chat:sid_abc123:dialog_xyz"`
/// - Feishu: `"feishu:oc_123456:dialog_xyz"`
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct UnifiedSessionId {
    pub channel: String,
    pub chat_id: String,
    pub dialog_id: String,
}

impl UnifiedSessionId {
    /// Create a new UnifiedSessionId
    pub fn new(
        channel: impl Into<String>,
        chat_id: impl Into<String>,
        dialog_id: impl Into<String>,
    ) -> Self {
        Self {
            channel: channel.into(),
            chat_id: chat_id.into(),
            dialog_id: dialog_id.into(),
        }
    }

    /// Parse from string format "channel:chat_id:dialog_id"
    pub fn parse(s: &str) -> Option<Self> {
        let parts: Vec<&str> = s.split(':').collect();
        if parts.len() != 3 {
            return None;
        }
        Some(Self {
            channel: parts[0].to_string(),
            chat_id: parts[1].to_string(),
            dialog_id: parts[2].to_string(),
        })
    }

    /// Get the session key without dialog_id (channel:chat_id)
    /// This is used to group all dialogs within a chat
    pub fn chat_scope(&self) -> String {
        format!("{}:{}", self.channel, self.chat_id)
    }
}

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

// Note: No Deref implementation to avoid confusion between String and UnifiedSessionId

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new() {
        let id = UnifiedSessionId::new("cli_chat", "sid123", "dialog456");
        assert_eq!(id.channel, "cli_chat");
        assert_eq!(id.chat_id, "sid123");
        assert_eq!(id.dialog_id, "dialog456");
    }

    #[test]
    fn test_parse() {
        let id = UnifiedSessionId::parse("cli_chat:sid123:dialog456").unwrap();
        assert_eq!(id.channel, "cli_chat");
        assert_eq!(id.chat_id, "sid123");
        assert_eq!(id.dialog_id, "dialog456");
    }

    #[test]
    fn test_parse_invalid() {
        assert!(UnifiedSessionId::parse("invalid").is_none());
        assert!(UnifiedSessionId::parse("only:two").is_none());
    }

    #[test]
    fn test_to_string() {
        let id = UnifiedSessionId::new("feishu", "oc123", "dialog789");
        assert_eq!(id.to_string(), "feishu:oc123:dialog789");
    }

    #[test]
    fn test_chat_scope() {
        let id = UnifiedSessionId::new("feishu", "oc123", "dialog789");
        assert_eq!(id.chat_scope(), "feishu:oc123");
    }
}
