use crate::core::{
    actually_used_field::ActuallyUsedField,
    bounds::FieldBounds,
    circuits::traits::arithmetic_circuit::ArithmeticCircuit,
    expressions::{expr::EvalFailure, field_expr::FieldExpr},
    global_value::value::FieldValue,
};

#[derive(Debug, Clone)]
pub struct AbsCircuit;

impl<F: ActuallyUsedField> ArithmeticCircuit<F> for AbsCircuit {
    fn eval(&self, x: Vec<F>) -> Result<Vec<F>, EvalFailure> {
        Ok(vec![FieldExpr::Abs(x[0]).eval()?])
    }

    fn bounds(&self, bounds: Vec<FieldBounds<F>>) -> Vec<FieldBounds<F>> {
        vec![FieldExpr::Abs(bounds[0]).bounds()]
    }

    fn run(&self, vals: Vec<FieldValue<F>>) -> Vec<FieldValue<F>> {
        vec![FieldValue::new(FieldExpr::Abs(vals[0]))]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        core::circuits::traits::arithmetic_circuit::tests::TestedArithmeticCircuit,
        ArcisField,
    };
    use rand::Rng;
    impl TestedArithmeticCircuit<ArcisField> for AbsCircuit {
        fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
            AbsCircuit
        }

        fn gen_n_inputs<R: Rng + ?Sized>(&self, _rng: &mut R) -> usize {
            1
        }
    }

    #[test]
    fn tested() {
        AbsCircuit::test(1, 64)
    }
}
