Documentation
use std::fmt::Debug;
use std::sync::OnceLock;

use async_trait::async_trait;
use regex::Regex;
use ricq::handler::QEvent;
use tokio::sync::broadcast::{channel, Receiver, Sender};
use tracing::{error, info, warn};

use crate::contact::member::{AnonymousMember, NamedMember};
use crate::event::{ClientLoginEvent, Event, FriendMessageEvent, GroupMessageEvent};
use crate::global_listener_worker;
use crate::{global_listener_runtime, global_status, Client};

static GLOBAL_EVENT_CHANNEL: OnceLock<Sender<Event>> = OnceLock::<Sender<Event>>::new();

pub fn global_sender() -> &'static Sender<Event> {
    GLOBAL_EVENT_CHANNEL.get_or_init(|| {
        let channel = channel(128);

        channel.0
    })
}

pub fn global_receiver() -> Receiver<Event> {
    global_sender().subscribe()
}

pub struct GlobalEventBroadcastHandler;

#[async_trait]
impl ricq::handler::Handler for GlobalEventBroadcastHandler {
    async fn handle(&self, event: QEvent) {
        let client: Client;

        fn get_client(id: i64) -> Option<Client> {
            global_status().clients.get(&id).map(|b| b.clone())
        }

        macro_rules! get_client {
            ($client:expr) => {
                if let Some(b) = global_status()
                    .clients
                    .get(&$client.uin().await)
                    .map(|b| b.clone())
                {
                    b
                } else {
                    return;
                }
            };
        }

        let self_event = match event {
            QEvent::Login(id) => {
                client = if let Some(b) = get_client(id) {
                    b
                } else {
                    return;
                };

                let base = ClientLoginEvent::from(client);
                Event::ClientLogin(base)
            }
            QEvent::GroupMessage(e) => {
                fn get_filter_regex() -> &'static Regex {
                    static FILTER_REGEX: OnceLock<Regex> = OnceLock::new();
                    FILTER_REGEX.get_or_init(|| Regex::new("<[$&].+>").expect("Cannot parse regex"))
                }

                client = get_client!(e.client);
                let group_id = e.inner.group_code;

                let group_name = || get_filter_regex().replace_all(&e.inner.group_name, "");

                let message = || e.inner.elements.to_string().replace('\n', "\\n");

                if client.id() == e.inner.from_uin {
                    info!(
                        "{client} >> 群 {}({}): {}",
                        group_name(),
                        group_id,
                        message(),
                    );
                    return;
                }

                let Some(group) = client.find_or_refresh_group(group_id).await else {
                    cannot_find_group(group_id);
                    error_more_info(&e);

                    return;
                };

                let sender = e.inner.from_uin;

                let member: Option<NamedMember>;
                let nick = if sender == AnonymousMember::ID {
                    "匿名"
                } else {
                    member = group.try_refresh_member(sender).await.unwrap_or_else(|e| {
                        warn!("获取群成员({})发生错误: {}", sender, e);
                        None
                    });

                    if let Some(m) = &member {
                        m.nickname()
                    } else {
                        warn!("群成员({})信息获取失败", sender);
                        return;
                    }
                };

                info!(
                    "{}({}) >> 群 {}({}) >> {client}: {}",
                    nick,
                    sender,
                    group_name(),
                    group_id,
                    message(),
                );

                let base = GroupMessageEvent::from(group, e);
                Event::GroupMessage(base)
            }
            QEvent::FriendMessage(e) => {
                client = get_client!(e.client);

                let friend_id = e.inner.from_uin;

                let Some(friend) = client.find_or_refresh_friend_list(friend_id).await else {
                    return;
                };

                info!(
                    "好友 {}({}) >> {client}: {}",
                    friend.nickname(),
                    friend.id(),
                    e.inner.elements,
                );

                let base = FriendMessageEvent::from(friend, e);

                Event::FriendMessage(base)
            }
            QEvent::DeleteFriend(e) => {
                client = get_client!(e.client);

                client.remove_friend_cache(e.inner.uin);

                Event::Unknown(QEvent::DeleteFriend(e).into())
            }
            QEvent::GroupDisband(e) => {
                client = get_client!(e.client);

                let group_id = e.inner.group_code;
                let op_id = e.inner.operator_uin;

                if let Some(g) = client.find_group(group_id) {
                    let member = g.find_member(e.inner.operator_uin);

                    let name = member
                        .map(|n| n.card_name().to_owned())
                        .unwrap_or_else(|| op_id.to_string());
                    info!("群 {}({})解散, 操作人: {}", g.name(), g.id(), name);
                } else {
                    info!("群({})解散, 操作人: {}", group_id, op_id);
                }

                client.remove_group_cache(e.inner.group_code);

                Event::Unknown(QEvent::GroupDisband(e).into())
            }
            QEvent::NewMember(e) => {
                client = get_client!(e.client);
                let group_id = e.inner.group_code;
                let member_id = e.inner.member_uin;

                let Some(group) = client.find_or_refresh_group(group_id).await else {
                    cannot_find_group(group_id);
                    error_more_info(&e);

                    return;
                };

                if member_id == client.id() {
                } else {
                    let _member = group.refresh_member(member_id).await;
                }

                Event::Unknown(QEvent::NewMember(e).into())
            }
            QEvent::GroupLeave(e) => {
                client = get_client!(e.client);
                let group_id = e.inner.group_code;
                let member = e.inner.member_uin;
                if member == client.id() {
                    client.remove_group_cache(group_id);
                } else {
                }

                Event::Unknown(QEvent::GroupLeave(e).into())
            }
            QEvent::KickedOffline(e) => {
                client = get_client!(e.client);

                info!("{}下线, Kicked: {:?}", client, e);

                global_status().remove_client(client.id());

                Event::Unknown(QEvent::KickedOffline(e).into())
            }
            QEvent::MSFOffline(e) => {
                client = get_client!(e.client);

                info!("{}下线, MSF: {:?}", client, e);

                global_status().remove_client(client.id());

                Event::Unknown(QEvent::MSFOffline(e).into())
            }
            or => Event::Unknown(or.into()),
        };

        global_listener_runtime().spawn(async move {
            global_listener_worker().handle(&self_event).await;

            let _ = global_sender().send(self_event);
        });
    }
}

fn cannot_find_group(group_id: i64) {
    error!("无法找到群({}), 这是一个Bug, 请报告此问题", group_id);
}

fn error_more_info<D: Debug>(d: &D) {
    error!("额外信息: {:?}", d);
}