Documentation
use crate::Context;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;

#[async_trait::async_trait]
pub trait Event: Debug + Sync {
    async fn call(&self, ctx: &mut Context) -> anyhow::Result<()>;
}

#[async_trait::async_trait]
pub trait EventOnce: Debug + Sync {
    async fn call(self: Box<Self>, ctx: &mut Context) -> anyhow::Result<()>;
}

// ---------------- 事件扩展 ---------------
#[async_trait::async_trait]
pub trait EventExt<T>: Sync {
    async fn call(&self, ctx: &mut Context, input: &mut T) -> anyhow::Result<()>;
}
pub struct EventExtLayer<T, E> {
    inner: E,
    _marker: PhantomData<T>,
}
impl<T, E> Debug for EventExtLayer<T, E> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EventExtLayer").finish_non_exhaustive()
    }
}
impl<T, E> EventExtLayer<T, E> {
    pub fn new(event: E) -> Self {
        Self {
            inner: event,
            _marker: PhantomData,
        }
    }
}
#[async_trait::async_trait]
impl<T, E> Event for EventExtLayer<T, E>
where
    E: EventExt<T> + Send + 'static,
    T: Debug + Sync + Send + 'static,
{
    async fn call(&self, ctx: &mut Context) -> anyhow::Result<()> {
        let mut input = if let Some(input) = ctx.try_into_inner::<T>() {
            input
        } else {
            return Err(anyhow::anyhow!("input is nil or is not T"));
        };
        let result = self.inner.call(ctx, &mut input).await;
        if ctx.is_empty_input() {
            ctx.set_input(input);
        }
        result
    }
}

#[async_trait::async_trait]
pub trait EventOnceExt<T>: Sync {
    async fn call(self, ctx: &mut Context, input: &mut T) -> anyhow::Result<()>;
}
pub struct EventOnceExtLayer<T, E> {
    inner: E,
    _marker: PhantomData<T>,
}
impl<T, E> Debug for EventOnceExtLayer<T, E> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EventOnceExtLayer").finish_non_exhaustive()
    }
}
impl<T, E> EventOnceExtLayer<T, E> {
    pub fn new(event: E) -> Self {
        Self {
            inner: event,
            _marker: PhantomData,
        }
    }
}
#[async_trait::async_trait]
impl<T, E> EventOnce for EventOnceExtLayer<T, E>
where
    E: EventOnceExt<T> + Sync + Send + 'static,
    T: Debug + Sync + Send + 'static,
{
    async fn call(self: Box<Self>, ctx: &mut Context) -> anyhow::Result<()> {
        let mut input = if let Some(input) = ctx.try_into_inner::<T>() {
            input
        } else {
            return Err(anyhow::anyhow!("input is nil or is not T"));
        };
        let result = self.inner.call(ctx, &mut input).await;
        if ctx.is_empty_input() {
            ctx.set_input(input);
        }
        result
    }
}

// ---------------- lambda 表达式扩展 ---------------
#[async_trait::async_trait]
impl<T, I, F> EventExt<I> for T
where
    T: Fn(&mut Context, &mut I) -> F + Sync + Send + 'static,
    I: Sync + Send + 'static,
    F: Future<Output = Result<(), anyhow::Error>> + Send,
{
    async fn call(&self, ctx: &mut Context, input: &mut I) -> anyhow::Result<()> {
        (self)(ctx, input).await
    }
}

#[async_trait::async_trait]
impl<T, I, F> EventOnceExt<I> for T
where
    T: FnOnce(&mut Context, &mut I) -> F + Sync + Send + 'static,
    I: Sync + Send + 'static,
    F: Future<Output = Result<(), anyhow::Error>> + Send,
{
    async fn call(self, ctx: &mut Context, input: &mut I) -> anyhow::Result<()> {
        (self)(ctx, input).await
    }
}