use samaharam::Bn254;
use samaharam::config::Srs;
use samaharam::crypto::{AccumulatedProof, ProofAccumulator};
use samaharam::adapters::{JfPlonkProof, parse_g1_uncompressed, ExternalProof};
use group::{Curve, Group};
use halo2curves::bn256::{Fr, G1, G2};
use rand::rngs::OsRng;
use ff::Field;

// Helper to create valid-looking random points
fn random_g1() -> <Bn254 as samaharam::traits::PairingEngine>::G1Affine {
    G1::random(OsRng).to_affine()
}

// Local mock SRS helper since internal Srs::mock is not exported
fn mock_srs(size: usize) -> Srs<Bn254> {
    let tau = Fr::random(OsRng);
    let g1_gen = G1::generator();
    let g2_gen = G2::generator();

    let mut powers_g1 = Vec::with_capacity(size);
    let mut current = Fr::ONE;
    for _ in 0..size {
        powers_g1.push((g1_gen * current).to_affine());
        current *= tau;
    }

    Srs::from_ceremony(
        powers_g1,
        (g2_gen * tau).to_affine(),
        g2_gen.to_affine(),
    )
}

#[test]
fn adversarial_identity_proof_fails_verification() {
    // Attack: User submits an AccumulatedProof consisting entirely of Identity points
    // hoping the pairing check e(0, G2) == e(0, tau) (1==1) passes.
    
    let proof = AccumulatedProof::<Bn254> {
        adjusted_commitment: G1::identity().to_affine(),
        combined_quotient: G1::identity().to_affine(),
        count: 1,
    };

    let srs = mock_srs(10);
    
    // This should pass mathematically checking e(0, G2) * e(0, tau) == 1
    let result = ProofAccumulator::<Bn254>::verify_accumulated(
        &proof, 
        &srs.g2_generator, 
        &srs.tau_g2
    );

    // CONFIRMS Finding #1: Identity proof is valid
    assert!(result, "Identity proof should mathematically verify");
}

#[test]
fn adversarial_malformed_point_deserialization() {
    // Attack: Feed bytes that do not represent a valid curve point
    let bad_bytes = [0xFFu8; 64]; 
    
    // Using public API
    let result = parse_g1_uncompressed(&bad_bytes);
    assert!(result.is_err());
}

#[test]
fn adversarial_short_evaluations() {


    // Attack: Provide fewer evaluations than wire commitments.
    // The previous code had `unwrap_or(Fr::from(1))`.
    // We want to see if we can trigger that or if validation catches it.

    let proof = JfPlonkProof {
        wire_commits: vec![random_g1(), random_g1()], // 2 wires
        prod_perm_poly_commit: random_g1(),
        split_quot_poly_commits: vec![random_g1()],
        opening_proof: random_g1(),
        shifted_opening_proof: random_g1(),
        poly_evals: vec![Fr::from(1u64)], // Only 1 evaluation! Missing 2nd.
        public_inputs: vec![],
    };

    // This should fail validation
    // If it passes validation effectively, that's a finding.
    let result = proof.validate_format();
    
    // Expect error: "Not enough evaluations"
    assert!(result.is_err(), "Should reject proof with insufficient evaluations");
}

#[test]
fn adversarial_wrong_domain_transcript() {
    // This simulates an attack where the Aggregator uses a different domain label
    // than the Verifier (or previous attempts).
    // Since we hardcoded "PLONK" in `aggregator.rs`, this test is ensuring deterministic behavior.
    
    // This is more of a consistency check than a direct exploit test without a full mock setup.
    // We'll skip complex setup for now.
}

#[test]
fn adversarial_kzg_identity_bypass() {
    use samaharam::crypto::{KzgScheme, KzgCommitment, KzgProof};
    use samaharam::backend::bn254::Bn254;
    use halo2curves::bn256::{Fr, G1};
    use group::Group;

    // Use the existing mock_srs helper
    let srs = mock_srs(8);
    let kzg_srs = samaharam::crypto::KzgSrs {
        powers_of_tau_g1: srs.powers_of_tau_g1,
        tau_g2: srs.tau_g2,
        g2_generator: srs.g2_generator,
    };
    let scheme = KzgScheme::<Bn254>::new(kzg_srs);

    // Identity Commit, Point 0, Value 0, Identity Proof
    let commitment = KzgCommitment { point: G1::identity().to_affine() };
    let point = Fr::from(0u64);
    let value = Fr::from(0u64);
    let proof = KzgProof { quotient: G1::identity().to_affine() };

    // Use the patched KzgScheme verifying verification failure
    let result = scheme.verify(&commitment, &point, &value, &proof);
    
    // Regression Test: Verify returns FALSE (Identity point rejected)
    assert!(!result, "Identity proof MUST be rejected by patched verifier");
}
