use std::{future::Future, pin::Pin, sync::Arc};

use tokio_util::sync::CancellationToken;

use crate::error::ProcessResult;

#[allow(async_fn_in_trait)]
pub trait ProcessHandler: Send + Sync + 'static {
    fn call(
        &self,
        cancellation: CancellationToken,
    ) -> impl Future<Output = ProcessResult> + Send;
}

pub(crate) trait AsyncProcess: Send + Sync {
    fn call_async(
        &self,
        cancellation: CancellationToken,
    ) -> Pin<Box<dyn Future<Output = ProcessResult> + Send + '_>>;
}

impl<E: ProcessHandler> AsyncProcess for E {
    fn call_async(
        &self,
        cancellation: CancellationToken,
    ) -> Pin<Box<dyn Future<Output = ProcessResult> + Send + '_>> {
        Box::pin(self.call(cancellation))
    }
}

#[derive(Clone)]
pub(crate) struct SharedProcess {
    pub(crate) process: Arc<dyn AsyncProcess + Send + Sync + 'static>,
}

pub(crate) trait IntoProcess {
    fn into_process(self) -> SharedProcess;
}

impl<E: ProcessHandler> IntoProcess for E {
    fn into_process(self) -> SharedProcess {
        SharedProcess {
            process: Arc::new(self),
        }
    }
}
