//! Contains the wrappers that give the public API to the users.

use super::assertion_impl::AssertionImpl;
use super::should::{Should, ShouldImpl};

/// Wrapper with a method to add an explanation.
/// This can of assertion cannot be chained.
#[derive(Debug)]
pub struct ConsumingAssert<T>(pub T)
where
    T: AssertionImpl;

impl<T> ConsumingAssert<T>
where
    T: AssertionImpl,
{
    /// Add an explanation to the current assertion.
    pub fn because(self, message: &'static str) {
        let mut implem = self.0;

        implem.should_mut().info.explanation = Some(message);
        if let Some(msg) = implem.failure_message() {
            implem.should_mut().add_message(msg);
        }

        drop(implem.consume_as_should())
    }
}

/// Wrapper with a method to add an explanation, just as `ConsumingAssert`,
/// but it also has a method to chain another assertion using the same
/// left element.
#[derive(Debug)]
pub struct ChainableAssert<T>(pub T)
where
    T: AssertionImpl;

impl<T> ChainableAssert<T>
where
    T: AssertionImpl,
{
    /// Add an explanation to the current assertion.
    pub fn because(self, message: &'static str) {
        let mut implem = self.0;

        implem.should_mut().info.explanation = Some(message);
        if let Some(msg) = implem.failure_message() {
            implem.should_mut().add_message(msg);
        }

        drop(implem.consume_as_should())
    }

    /// Add another assertion using the same left element.
    pub fn and_should(self) -> Should<<T as AssertionImpl>::Left> {
        let mut implem = self.0;

        let msg = implem.failure_message();
        let mut should = implem.consume_as_should();
        if let Some(msg) = msg {
            should.add_message(msg);
        }
        let ShouldImpl { left, info, .. } = should;

        Should(ShouldImpl {
            left,
            info,
            truthness: true,
        })
    }
}
