use super::*;
impl<E: Environment, const NUM_BITS: u8> Hash for Pedersen<E, NUM_BITS> {
    type Input = Boolean<E>;
    type Output = Field<E>;
    fn hash(&self, input: &[Self::Input]) -> Self::Output {
        self.hash_uncompressed(input).to_x_coordinate()
    }
}
impl<E: Environment, const NUM_BITS: u8> Metrics<dyn Hash<Input = Boolean<E>, Output = Field<E>>>
    for Pedersen<E, NUM_BITS>
{
    type Case = Vec<Mode>;
    #[inline]
    fn count(case: &Self::Case) -> Count {
        count!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, case)
    }
}
impl<E: Environment, const NUM_BITS: u8> OutputMode<dyn Hash<Input = Boolean<E>, Output = Field<E>>>
    for Pedersen<E, NUM_BITS>
{
    type Case = Vec<Mode>;
    #[inline]
    fn output_mode(parameter: &Self::Case) -> Mode {
        output_mode!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, parameter)
    }
}
#[cfg(all(test, console))]
mod tests {
    use super::*;
    use snarkvm_circuit_types::environment::Circuit;
    use snarkvm_utilities::{TestRng, Uniform};
    const ITERATIONS: u64 = 10;
    const MESSAGE: &str = "PedersenCircuit0";
    const NUM_BITS_MULTIPLIER: u8 = 8;
    fn check_hash<const NUM_BITS: u8>(mode: Mode, rng: &mut TestRng) {
        use console::Hash as H;
        let native = console::Pedersen::<<Circuit as Environment>::Network, NUM_BITS>::setup(MESSAGE);
        let circuit = Pedersen::<Circuit, NUM_BITS>::constant(native.clone());
        for i in 0..ITERATIONS {
            let input = (0..NUM_BITS).map(|_| bool::rand(rng)).collect::<Vec<bool>>();
            let expected = native.hash(&input).expect("Failed to hash native input");
            let circuit_input: Vec<Boolean<_>> = Inject::new(mode, input);
            Circuit::scope(format!("Pedersen {mode} {i}"), || {
                let candidate = circuit.hash(&circuit_input);
                assert_eq!(expected, candidate.eject_value());
                let modes = circuit_input.iter().map(|b| b.eject_mode()).collect::<Vec<_>>();
                assert_count!(
                    Pedersen<Circuit, NUM_BITS>,
                    HashUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>>,
                    &modes
                );
                assert_output_mode!(
                    Pedersen<Circuit, NUM_BITS>,
                    HashUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>>,
                    &modes,
                    candidate
                );
            });
        }
    }
    #[test]
    fn test_hash_constant() {
        let mut rng = TestRng::default();
        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Constant, &mut rng);
        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
    }
    #[test]
    fn test_hash_public() {
        let mut rng = TestRng::default();
        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Public, &mut rng);
        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
    }
    #[test]
    fn test_hash_private() {
        let mut rng = TestRng::default();
        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Private, &mut rng);
        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
    }
}