#[cfg(feature = "float")]
pub mod precision;

use self::fluid::core::prelude::*;
use crate as fluid;
use std::ops::Not;

#[derive(Debug, Drop)]
pub struct BeEqualTo<L: Debug, R: Debug>
where
    L: PartialEq<R>,
{
    should: ShouldImpl<L>,
    right: R,
}

impl<L: Debug, R: Debug> AssertionImpl for BeEqualTo<L, R>
where
    L: PartialEq<R>,
{
    type Left = L;

    fn failure_message(&mut self) -> Option<String> {
        let left_dbg = self.should.left_dbg();
        let right_dbg = self.right.dbg().to_string();
        let truthness = self.should.truthness();

        if (self.should.left.as_ref()? == &self.right) != truthness {
            let message = if let Some(stringified) = self.should.stringified() {
                if left_dbg != right_dbg {
                    format!(
                        "\t{} has the value {}.\n\
                         \tIt should{} be equal to {} but it is{}.",
                        stringified,
                        left_dbg,
                        truthness.str(),
                        right_dbg,
                        truthness.not().str()
                    )
                } else {
                    format!(
                        "\t{} is equal to {}\n\
                         \tbut it should{}.",
                        stringified,
                        left_dbg,
                        truthness.str()
                    )
                }
            } else {
                format!(
                    "\t{} is{} equal to {}.",
                    left_dbg,
                    truthness.not().str(),
                    right_dbg
                )
            };

            Some(message)
        } else {
            None
        }
    }

    fn consume_as_should(mut self) -> ShouldImpl<Self::Left> {
        self.should.take()
    }

    fn should_mut(&mut self) -> &mut ShouldImpl<Self::Left> {
        &mut self.should
    }
}

impl<L: Debug> Should<L> {
    /// Checks if the left field is equal to the right field.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use fluid::prelude::*;
    /// fn the_answer() -> i32 {
    ///     42
    /// }
    ///
    /// the_answer().should().be_equal_to(42);
    /// ```
    pub fn be_equal_to<R: Debug>(self, right: R) -> ChainableAssert<BeEqualTo<L, R>>
    where
        L: PartialEq<R>,
    {
        let implem = BeEqualTo {
            should: self.into(),
            right,
        };

        ChainableAssert(implem)
    }
}
