Documentation
use crate::error::{AtriError, AtriResult};
use crate::message::image::Image;
use crate::message::meta::MetaMessage;
use crate::message::MessageChain;
use crate::Client;
use ricq::structs::{FriendInfo, MessageReceipt};
use std::sync::Arc;
use tracing::error;

#[derive(Clone)]
pub struct Friend(Arc<imp::Friend>);

impl Friend {
    pub fn id(&self) -> i64 {
        self.0.info.uin
    }

    pub fn nickname(&self) -> &str {
        &self.0.info.nick
    }

    pub fn remark(&self) -> &str {
        &self.0.info.remark
    }

    pub fn client(&self) -> &Client {
        &self.0.client
    }

    pub async fn delete(&self) -> bool {
        let result = self
            .client()
            .request_client()
            .delete_friend(self.id())
            .await;

        if let Err(e) = result {
            error!(
                "尝试删除好友 {}({}) 时失败: {:?}",
                self.nickname(),
                self.id(),
                e
            );
            return false;
        }

        let map = self.client().remove_friend_cache(self.id());

        map.is_some()
    }

    pub async fn send_message(&self, chain: MessageChain) -> AtriResult<MessageReceipt> {
        let result = self
            .client()
            .request_client()
            .send_friend_message(self.id(), chain.into())
            .await;

        if let Err(ref e) = result {
            error!(
                "{}发送消息失败, 目标好友: {}({}), {:?}",
                self.client(),
                self.nickname(),
                self.id(),
                e
            );
        }

        result.map_err(AtriError::from)
    }

    pub async fn upload_image(&self, image: Vec<u8>) -> AtriResult<Image> {
        let f = self
            .client()
            .request_client()
            .upload_friend_image(self.id(), image)
            .await?;

        Ok(Image::Friend(f))
    }

    pub async fn recall_message<M: MetaMessage>(&self, msg: &M) -> AtriResult<()> {
        let meta = msg.metadata();
        self.client()
            .request_client()
            .recall_friend_message(
                self.id(),
                meta.time as i64,
                meta.seqs.clone(),
                meta.rands.clone(),
            )
            .await
            .map_err(AtriError::from)
    }

    pub(crate) fn from(client: Client, info: FriendInfo) -> Self {
        let f = imp::Friend { client, info };

        Self(Arc::new(f))
    }
}

mod imp {
    use crate::Client;
    use ricq::structs::FriendInfo;

    pub struct Friend {
        pub client: Client,
        pub info: FriendInfo,
    }
}