use super::super::problem::*;

impl From<Problem> for anyhow::Error {
    fn from(problem: Problem) -> Self {
        if !problem.causes.is_empty() {
            let mut causes = problem.into_iter().rev();
            let root_cause = causes.next().expect("root cause");
            let mut anyhow_error = anyhow::Error::from_boxed(root_cause.error);
            for cause in causes {
                anyhow_error = anyhow_error.context(cause.error);
            }
            anyhow_error
        } else {
            problem.into_error().into()
        }
    }
}

//
// AnyhowIntoProblem
//

/// Into problem.
pub trait AnyhowIntoProblem {
    /// Into problem.
    fn into_problem(self) -> Problem;
}

impl AnyhowIntoProblem for anyhow::Error {
    #[track_caller]
    fn into_problem(self) -> Problem {
        Problem::new(self.into())
    }
}

//
// AnyhowIntoProblemResult
//

/// Into [Result]\<_, [Problem]\>.
pub trait AnyhowIntoProblemResult<OkT> {
    /// Into [Result]\<_, [Problem]\>.
    fn into_problem(self) -> Result<OkT, Problem>;
}

impl<OkT> AnyhowIntoProblemResult<OkT> for anyhow::Result<OkT> {
    #[track_caller]
    fn into_problem(self) -> Result<OkT, Problem> {
        // Note that we are *not* using map_err() here because a closure cannot be annotated with #[track_caller]
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(error.into_problem()),
        }
    }
}
