Skip to content
use qrcode::QrCode;
use qrcode::render::svg;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};

static BATTLE_PIN_COUNTER: AtomicU64 = AtomicU64::new(1013);

#[must_use]
pub fn generate_battle_pin() -> String {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_nanos();
    let count = BATTLE_PIN_COUNTER.fetch_add(7919, Ordering::Relaxed);
    #[allow(clippy::cast_possible_truncation)]
    let val = ((nanos ^ (u128::from(count) * 1_000_003)) % 900_000 + 100_000) as u32;
    format!("{val:06}")
}

pub fn generate_qr_svg(payload: &str) -> Result<String, String> {
    let code =
        QrCode::new(payload.as_bytes()).map_err(|e| format!("Failed to generate QR code: {e}"))?;

    let svg_xml = code
        .render::<svg::Color>()
        .min_dimensions(200, 200)
        .dark_color(svg::Color("#4a3828"))
        .light_color(svg::Color("#fbf8f2"))
        .build();

    Ok(svg_xml)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_generate_battle_pin_format() {
        let pin = generate_battle_pin();
        assert_eq!(pin.len(), 6);
        assert!(pin.chars().all(|c| c.is_ascii_digit()));
    }

    #[test]
    fn test_generate_qr_svg_produces_svg() {
        let svg = generate_qr_svg("https://example.com/battle?pin=123456").unwrap();
        assert!(svg.contains("<svg"));
        assert!(svg.contains("</svg>"));
        assert!(svg.contains("#4a3828"));
    }
}