use crate::{
    core::{
        actually_used_field::ActuallyUsedField,
        bounds::FieldBounds,
        circuits::traits::{
            arithmetic_circuit::ArithmeticCircuit,
            general_circuit::GeneralCircuit,
        },
        expressions::expr::EvalFailure,
        global_value::value::FieldValue,
    },
    utils::{
        field::{BaseField, ScalarField},
        used_field::UsedField,
    },
};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[allow(dead_code)]
pub struct IdentityCircuit;

impl Default for IdentityCircuit {
    fn default() -> Self {
        Self
    }
}

impl GeneralCircuit for IdentityCircuit {
    fn eval(
        &self,
        scalars: Vec<ScalarField>,
        bases: Vec<BaseField>,
    ) -> Result<(Vec<ScalarField>, Vec<BaseField>), EvalFailure> {
        Ok((scalars, bases))
    }

    fn bounds(
        &self,
        scalar_bounds: Vec<FieldBounds<ScalarField>>,
        base_bounds: Vec<FieldBounds<BaseField>>,
    ) -> (Vec<FieldBounds<ScalarField>>, Vec<FieldBounds<BaseField>>) {
        (scalar_bounds, base_bounds)
    }

    fn run(
        &self,
        scalar_vals: Vec<FieldValue<ScalarField>>,
        base_vals: Vec<FieldValue<BaseField>>,
    ) -> (Vec<FieldValue<ScalarField>>, Vec<FieldValue<BaseField>>) {
        (scalar_vals, base_vals)
    }
}

impl<F: UsedField> ArithmeticCircuit<F> for IdentityCircuit {
    fn eval(&self, x: Vec<F>) -> Result<Vec<F>, EvalFailure> {
        Ok(x)
    }

    fn bounds(&self, bounds: Vec<FieldBounds<F>>) -> Vec<FieldBounds<F>> {
        bounds
    }

    fn run(&self, vals: Vec<FieldValue<F>>) -> Vec<FieldValue<F>>
    where
        F: ActuallyUsedField,
    {
        vals
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::circuits::traits::general_circuit::tests::TestedGeneralCircuit;
    use rand::Rng;

    fn gen_usize<R: Rng + ?Sized>(rng: &mut R) -> usize {
        let mut result = 0;
        while rng.gen_bool(0.875) {
            result += 1;
        }
        result
    }

    impl TestedGeneralCircuit for IdentityCircuit {
        fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
            Self
        }

        fn gen_n_scalars<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
            gen_usize(rng)
        }

        fn gen_n_bases<R: Rng + ?Sized>(&self, rng: &mut R, _n_scalars: usize) -> usize {
            gen_usize(rng)
        }
    }
    #[test]
    fn tested() {
        IdentityCircuit::test(1, 1)
    }
}
