use crate::prelude::{Deserialize, DeserializeOwned, Serialize};
use snarkvm_curves::{
    bls12_377::Bls12_377,
    edwards_bls12::{EdwardsAffine, EdwardsParameters},
    AffineCurve,
    MontgomeryParameters,
    PairingEngine,
    ProjectiveCurve,
    TwistedEdwardsParameters,
};
use snarkvm_fields::{PrimeField, SquareRootField};
use snarkvm_utilities::BigInteger;
use core::{fmt::Debug, hash::Hash};
use zeroize::Zeroize;
pub trait Environment:
    'static + Copy + Clone + Debug + PartialEq + Eq + Hash + Serialize + DeserializeOwned + Send + Sync
{
    type Affine: AffineCurve<
            Projective = Self::Projective,
            BaseField = Self::Field,
            ScalarField = Self::Scalar,
            Coordinates = (Self::Field, Self::Field),
        >;
    type BigInteger: BigInteger;
    type Field: PrimeField<BigInteger = Self::BigInteger> + SquareRootField + Copy + Zeroize;
    type PairingCurve: PairingEngine<Fr = Self::Field>;
    type Projective: ProjectiveCurve<Affine = Self::Affine, BaseField = Self::Field, ScalarField = Self::Scalar>;
    type Scalar: PrimeField<BigInteger = Self::BigInteger> + Copy + Zeroize;
    const EDWARDS_A: Self::Field;
    const EDWARDS_D: Self::Field;
    const MONTGOMERY_A: Self::Field;
    const MONTGOMERY_B: Self::Field;
    const MAX_STRING_BYTES: u32 = u8::MAX as u32;
    fn halt<S: Into<String>, T>(message: S) -> T {
        panic!("{}", message.into())
    }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Console;
impl Environment for Console {
    type Affine = EdwardsAffine;
    type BigInteger = <Self::Field as PrimeField>::BigInteger;
    type Field = <Self::Affine as AffineCurve>::BaseField;
    type PairingCurve = Bls12_377;
    type Projective = <Self::Affine as AffineCurve>::Projective;
    type Scalar = <Self::Affine as AffineCurve>::ScalarField;
    const EDWARDS_A: Self::Field = <EdwardsParameters as TwistedEdwardsParameters>::EDWARDS_A;
    const EDWARDS_D: Self::Field = <EdwardsParameters as TwistedEdwardsParameters>::EDWARDS_D;
    const MONTGOMERY_A: Self::Field = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_A;
    const MONTGOMERY_B: Self::Field = <EdwardsParameters as MontgomeryParameters>::MONTGOMERY_B;
}