Documentation
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;

use ricq::handler::QEvent;

use tracing::error;

use atri_ffi::ffi::FFIEvent;
use atri_ffi::ManagedCloneable;

use crate::contact::friend::Friend;
use crate::contact::group::Group;
use crate::contact::member::{AnonymousMember, Member};
use crate::contact::{Contact, ContactSubject};
use crate::message::MessageChain;
use crate::{Client, Listener};

pub mod custom;
pub mod listener;

#[derive(Clone)]
pub enum Event {
    ClientLogin(ClientLoginEvent),
    GroupMessage(GroupMessageEvent),
    FriendMessage(FriendMessageEvent),
    Unknown(SharedEvent<QEvent>),
}

impl Event {
    pub fn into_ffi(self) -> FFIEvent {
        macro_rules! ffi_get {
            ($($e:ident => $t:expr);* $(;)?) => {
                match self {
                    $(
                    Self::$e(e) => ($t, &e.event.intercepted as *const AtomicBool, ManagedCloneable::from_value(e)),
                    )*
                }
            };
        }

        let (t, intercepted, base) = ffi_get! {
            ClientLogin => 0;
            GroupMessage => 1;
            FriendMessage => 2;
            Unknown => 255;
        };

        FFIEvent::from(t, intercepted as _, base)
    }
}

macro_rules! event_impl {
    ($($variant:ident),* ;$name:ident: $ret:ty as $func:expr) => {
        impl Event {
            pub fn $name(&self) -> $ret {
                match self {
                    $(Self::$variant(e) => {
                        ($func)(e)
                    })*
                }
            }
        }
    };
}

macro_rules! event_fun_impl {
    ($($name:ident: $ret:ty as $func:expr);+ $(;)?) => {
        $(
        event_impl! {
            ClientLogin,
            GroupMessage,
            FriendMessage,
            Unknown;
            $name: $ret as $func
        }
        )*
    };
}

event_fun_impl! {
    intercept: () as SharedEvent::intercept;
    is_intercepted: bool as SharedEvent::is_intercepted;
}

impl FromEvent for Event {
    fn from_event(e: Event) -> Option<Self> {
        Some(e)
    }
}

#[derive(Debug)]
pub struct SharedEvent<T> {
    event: Arc<EventWithFlag<T>>,
}

impl<T> Clone for SharedEvent<T> {
    fn clone(&self) -> Self {
        Self {
            event: self.event.clone(),
        }
    }
}

#[derive(Debug)]
struct EventWithFlag<T> {
    intercepted: AtomicBool,
    inner: T,
}

impl<T> SharedEvent<T> {
    fn new(event: T) -> Self {
        Self {
            event: EventWithFlag {
                intercepted: AtomicBool::new(false),
                inner: event,
            }
            .into(),
        }
    }

    pub fn intercept(&self) {
        self.event.intercepted.store(true, Ordering::Relaxed);
    }

    pub fn is_intercepted(&self) -> bool {
        self.event.intercepted.load(Ordering::Relaxed)
    }

    pub fn try_into_inner(self) -> Result<T, Self> {
        let e = Arc::try_unwrap(self.event);

        match e {
            Ok(e) => Ok(e.inner),
            Err(arc) => Err(Self { event: arc }),
        }
    }
}

pub type GroupMessageEvent = SharedEvent<imp::GroupMessageEvent>;

impl GroupMessageEvent {
    pub fn group(&self) -> &Group {
        &self.event.inner.group
    }

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

    pub fn sender(&self) -> Member {
        let id = self.message().metadata().sender;
        if id == AnonymousMember::ID {
            if let Some(ano) = self.message().metadata().anonymous.clone() {
                let anom = AnonymousMember::from(self.group().clone(), ano);
                return Member::Anonymous(anom);
            } else {
                error!("无法找到匿名信息");
            }
        }

        self.group()
            .find_member(id)
            .map(Member::Named)
            .expect("Cannot find member")
    }

    pub fn message(&self) -> &MessageChain {
        &self.event.inner.message
    }

    pub async fn next_event<F>(&self, timeout: Duration, filter: F) -> Option<GroupMessageEvent>
    where
        F: Fn(&GroupMessageEvent) -> bool,
    {
        let group_id = self.group().id();
        let sender_id = self.sender().id();

        Listener::next_event(timeout, |e: &GroupMessageEvent| {
            if e.group().id() != group_id {
                return false;
            }

            if e.message().metadata().sender != sender_id {
                return false;
            }

            filter(e)
        })
        .await
    }

    pub async fn next_message<F>(&self, timeout: Duration, filter: F) -> Option<MessageChain>
    where
        F: Fn(&MessageChain) -> bool,
    {
        // todo: optimize
        self.next_event(timeout, |e| filter(e.message()))
            .await
            .map(|e| e.message().clone())
    }

    pub(crate) fn from(group: Group, ori: ricq::client::event::GroupMessageEvent) -> Self {
        Self::new(imp::GroupMessageEvent {
            group,
            message: ori.inner.into(),
        })
    }
}

impl ContactSubject for GroupMessageEvent {
    fn subject(&self) -> Contact {
        Contact::Group(self.group().clone())
    }
}

impl FromEvent for GroupMessageEvent {
    fn from_event(e: Event) -> Option<Self> {
        if let Event::GroupMessage(e) = e {
            Some(e)
        } else {
            None
        }
    }
}

pub type FriendMessageEvent = SharedEvent<imp::FriendMessageEvent>;

impl FriendMessageEvent {
    pub fn friend(&self) -> &Friend {
        &self.event.inner.friend
    }

    pub fn message(&self) -> &MessageChain {
        &self.event.inner.message
    }

    pub(crate) fn from(friend: Friend, ori: ricq::client::event::FriendMessageEvent) -> Self {
        let imp = imp::FriendMessageEvent {
            friend,
            message: ori.inner.into(),
        };

        Self::new(imp)
    }
}

impl FromEvent for FriendMessageEvent {
    fn from_event(e: Event) -> Option<Self> {
        if let Event::FriendMessage(e) = e {
            Some(e)
        } else {
            None
        }
    }
}

impl ContactSubject for FriendMessageEvent {
    fn subject(&self) -> Contact {
        Contact::Friend(self.friend().clone())
    }
}

pub type ClientLoginEvent = SharedEvent<imp::BotOnlineEvent>;

impl ClientLoginEvent {
    pub fn from(bot: Client) -> Self {
        Self::new(imp::BotOnlineEvent { bot })
    }
}

impl From<QEvent> for SharedEvent<QEvent> {
    fn from(value: QEvent) -> Self {
        Self::new(value)
    }
}

mod imp {

    use crate::contact::friend::Friend;
    use crate::contact::group::Group;
    use crate::message::MessageChain;
    use crate::Client;

    pub struct GroupMessageEvent {
        pub group: Group,
        pub message: MessageChain,
    }

    pub struct FriendMessageEvent {
        pub friend: Friend,
        pub message: MessageChain,
    }

    pub struct BotOnlineEvent {
        pub bot: Client,
    }
}

pub enum MessageEvent {
    Group(GroupMessageEvent),
    Friend(FriendMessageEvent),
}

impl FromEvent for MessageEvent {
    fn from_event(e: Event) -> Option<Self> {
        match e {
            Event::GroupMessage(e) => Some(Self::Group(e)),
            Event::FriendMessage(e) => Some(Self::Friend(e)),
            _ => None,
        }
    }
}

pub trait FromEvent: Sized {
    fn from_event(e: Event) -> Option<Self>;
}