use ldpc::{
    channel::{AwgnChannel, Channel},
    code::{CodeTopology, GenerationMethod, LdpcCode, LdpcParams},
    decoder::{build_decoder, DecoderConfig, DecoderMethod},
    encoder::{build_encoder, EncodingMethod},
};
use rand::{Rng, SeedableRng};

fn main() -> ldpc::Result<()> {
    // ── 1. Générer le code ────────────────────────────────────────────────────
    let params = LdpcParams {
        n: 100,
        k: 50,
        topology: CodeTopology::Regular { wc: 3, wr: 6 },
        generation: GenerationMethod::MacKayNeal { max_attempts: 500 },
        seed: Some(42),
    };
    let mut code = LdpcCode::new(params)?;
    println!(
        "Code LDPC : n={}, k={}, taux={:.2}, girth={}",
        code.n(),
        code.k(),
        code.rate(),
        code.girth()
    );

    // ── 2. Encodeur ───────────────────────────────────────────────────────────
    let encoder = build_encoder(&mut code, EncodingMethod::Systematic)?;

    // ── 3. Canal ──────────────────────────────────────────────────────────────
    let channel = AwgnChannel::new(2.0, code.rate())?; // 2 dB Eb/N0
    println!("Capacité AWGN ≈ {:.4} bits/utilisation", channel.capacity());

    // ── 4. Décodeur ───────────────────────────────────────────────────────────
    let decoder = build_decoder(&code, DecoderMethod::SumProduct, DecoderConfig::default());

    // ── 5. Simulation ─────────────────────────────────────────────────────────
    let mut rng = rand::rngs::StdRng::seed_from_u64(123);
    let n_trials = 100;
    let mut errors = 0usize;

    for _ in 0..n_trials {
        // Message aléatoire
        let message: Vec<u8> = (0..code.k()).map(|_| rng.gen::<u8>() & 1).collect();
        // Encodage
        let codeword = encoder.encode(&message)?;
        // Transmission AWGN
        let received_llr = channel.transmit(&codeword, &mut rng);
        // Décodage
        let result = decoder.decode(&received_llr);
        // Vérification
        if !result.is_success() {
            errors += 1;
        }
    }

    let ber = errors as f64 / n_trials as f64;
    println!("FER sur {} essais à 2dB : {:.2}%", n_trials, ber * 100.0);
    Ok(())
}
