use super::*;
use std::sync::atomic::{AtomicBool, Ordering};

struct ReadyState<T: Async> {
    set_completed: AtomicBool,
    result: Result<T::Output>,
}

impl<T: Async> ReadyState<T> {
    fn new(result: Result<T::Output>) -> Self {
        Self {
            set_completed: AtomicBool::new(false),
            result,
        }
    }

    fn status(&self) -> AsyncStatus {
        if self.result.is_ok() {
            AsyncStatus::Completed
        } else {
            AsyncStatus::Error
        }
    }

    // The "Ready" implementations don't need to store the handler since the handler is invoked immediately
    // but still need to confirm that `SetCompleted` is called at most once.
    fn invoke_completed(&self, sender: &T, handler: Ref<'_, T::CompletedHandler>) -> Result<()> {
        if !self.set_completed.swap(true, Ordering::SeqCst) {
            sender.invoke_completed(handler.ok()?, self.status());
            Ok(())
        } else {
            Err(Error::from_hresult(HRESULT(0x80000018u32 as i32))) // E_ILLEGAL_DELEGATE_ASSIGNMENT
        }
    }

    // The `From` implementation is not used here since we don't want to transfer any error object to the calling thread.
    // That happens when `GetResults` is called.
    fn error_code(&self) -> Result<HRESULT> {
        Ok(match &self.result {
            Ok(_) => HRESULT(0),
            Err(error) => error.code(),
        })
    }
}

#[implement(IAsyncAction, IAsyncInfo)]
struct ReadyAction(ReadyState<IAsyncAction>);

#[implement(IAsyncOperation<T>, IAsyncInfo)]
struct ReadyOperation<T>(ReadyState<IAsyncOperation<T>>)
where
    T: RuntimeType + 'static;

#[implement(IAsyncActionWithProgress<P>, IAsyncInfo)]
struct ReadyActionWithProgress<P>(ReadyState<IAsyncActionWithProgress<P>>)
where
    P: RuntimeType + 'static;

#[implement(IAsyncOperationWithProgress<T, P>, IAsyncInfo)]
struct ReadyOperationWithProgress<T, P>(ReadyState<IAsyncOperationWithProgress<T, P>>)
where
    T: RuntimeType + 'static,
    P: RuntimeType + 'static;

impl IAsyncInfo_Impl for ReadyAction_Impl {
    fn Id(&self) -> Result<u32> {
        Ok(1)
    }
    fn Status(&self) -> Result<AsyncStatus> {
        Ok(self.0.status())
    }
    fn ErrorCode(&self) -> Result<HRESULT> {
        self.0.error_code()
    }
    fn Cancel(&self) -> Result<()> {
        Ok(())
    }
    fn Close(&self) -> Result<()> {
        Ok(())
    }
}

impl<T: RuntimeType> IAsyncInfo_Impl for ReadyOperation_Impl<T> {
    fn Id(&self) -> Result<u32> {
        Ok(1)
    }
    fn Status(&self) -> Result<AsyncStatus> {
        Ok(self.0.status())
    }
    fn ErrorCode(&self) -> Result<HRESULT> {
        self.0.error_code()
    }
    fn Cancel(&self) -> Result<()> {
        Ok(())
    }
    fn Close(&self) -> Result<()> {
        Ok(())
    }
}

impl<P: RuntimeType> IAsyncInfo_Impl for ReadyActionWithProgress_Impl<P> {
    fn Id(&self) -> Result<u32> {
        Ok(1)
    }
    fn Status(&self) -> Result<AsyncStatus> {
        Ok(self.0.status())
    }
    fn ErrorCode(&self) -> Result<HRESULT> {
        self.0.error_code()
    }
    fn Cancel(&self) -> Result<()> {
        Ok(())
    }
    fn Close(&self) -> Result<()> {
        Ok(())
    }
}

impl<T: RuntimeType, P: RuntimeType> IAsyncInfo_Impl for ReadyOperationWithProgress_Impl<T, P> {
    fn Id(&self) -> Result<u32> {
        Ok(1)
    }
    fn Status(&self) -> Result<AsyncStatus> {
        Ok(self.0.status())
    }
    fn ErrorCode(&self) -> Result<HRESULT> {
        self.0.error_code()
    }
    fn Cancel(&self) -> Result<()> {
        Ok(())
    }
    fn Close(&self) -> Result<()> {
        Ok(())
    }
}

impl IAsyncAction_Impl for ReadyAction_Impl {
    fn SetCompleted(&self, handler: Ref<'_, AsyncActionCompletedHandler>) -> Result<()> {
        self.0.invoke_completed(&self.as_interface(), handler)
    }
    fn Completed(&self) -> Result<AsyncActionCompletedHandler> {
        Err(Error::empty())
    }
    fn GetResults(&self) -> Result<()> {
        self.0.result.clone()
    }
}

impl<T: RuntimeType> IAsyncOperation_Impl<T> for ReadyOperation_Impl<T> {
    fn SetCompleted(&self, handler: Ref<'_, AsyncOperationCompletedHandler<T>>) -> Result<()> {
        self.0.invoke_completed(&self.as_interface(), handler)
    }
    fn Completed(&self) -> Result<AsyncOperationCompletedHandler<T>> {
        Err(Error::empty())
    }
    fn GetResults(&self) -> Result<T> {
        self.0.result.clone()
    }
}

impl<P: RuntimeType> IAsyncActionWithProgress_Impl<P> for ReadyActionWithProgress_Impl<P> {
    fn SetCompleted(
        &self,
        handler: Ref<'_, AsyncActionWithProgressCompletedHandler<P>>,
    ) -> Result<()> {
        self.0.invoke_completed(&self.as_interface(), handler)
    }
    fn Completed(&self) -> Result<AsyncActionWithProgressCompletedHandler<P>> {
        Err(Error::empty())
    }
    fn GetResults(&self) -> Result<()> {
        self.0.result.clone()
    }
    fn SetProgress(&self, _: Ref<'_, AsyncActionProgressHandler<P>>) -> Result<()> {
        Ok(())
    }
    fn Progress(&self) -> Result<AsyncActionProgressHandler<P>> {
        Err(Error::empty())
    }
}

impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress_Impl<T, P>
    for ReadyOperationWithProgress_Impl<T, P>
{
    fn SetCompleted(
        &self,
        handler: Ref<'_, AsyncOperationWithProgressCompletedHandler<T, P>>,
    ) -> Result<()> {
        self.0.invoke_completed(&self.as_interface(), handler)
    }
    fn Completed(&self) -> Result<AsyncOperationWithProgressCompletedHandler<T, P>> {
        Err(Error::empty())
    }
    fn GetResults(&self) -> Result<T> {
        self.0.result.clone()
    }
    fn SetProgress(&self, _: Ref<'_, AsyncOperationProgressHandler<T, P>>) -> Result<()> {
        Ok(())
    }
    fn Progress(&self) -> Result<AsyncOperationProgressHandler<T, P>> {
        Err(Error::empty())
    }
}

impl IAsyncAction {
    /// Creates an `IAsyncAction` that is immediately ready with a value.
    pub fn ready(result: Result<()>) -> Self {
        ReadyAction(ReadyState::new(result)).into()
    }
}

impl<T: RuntimeType> IAsyncOperation<T> {
    /// Creates an `IAsyncOperation<T>` that is immediately ready with a value.
    pub fn ready(result: Result<T>) -> Self {
        ReadyOperation(ReadyState::new(result)).into()
    }
}

impl<P: RuntimeType> IAsyncActionWithProgress<P> {
    /// Creates an `IAsyncActionWithProgress<P>` that is immediately ready with a value.
    pub fn ready(result: Result<()>) -> Self {
        ReadyActionWithProgress(ReadyState::new(result)).into()
    }
}

impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress<T, P> {
    /// Creates an `IAsyncOperationWithProgress<T, P>` that is immediately ready with a value.
    pub fn ready(result: Result<T>) -> Self {
        ReadyOperationWithProgress(ReadyState::new(result)).into()
    }
}
