// Simple benchmark that doesn't depend on the full crate
mod base36_simple {

    const BASE36_CHARS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";

    // Lookup table for fast base36 to digit conversion
    const BASE36_DECODE: [u8; 256] = {
        let mut table = [255u8; 256];
        let mut i = 0;
        while i < 10 {
            table[(b'0' + i) as usize] = i;
            i += 1;
        }
        let mut i = 0;
        while i < 26 {
            table[(b'a' + i) as usize] = i + 10;
            i += 1;
        }
        table
    };

    #[inline(always)]
    pub fn u64_to_base36(mut value: u64) -> String {
        if value == 0 {
            return "0".to_string();
        }

        // Stack allocated buffer - no heap allocation until final string
        let mut buffer: [u8; 13] = [0; 13]; // Maximum length of u64 in base36 is 13
        let mut pos = 13;

        // Optimized division loop - compiler can optimize division by constant
        while value > 0 {
            pos -= 1;
            buffer[pos] = BASE36_CHARS[(value % 36) as usize];
            value /= 36;
        }

        // SAFETY: We only write valid ASCII characters
        unsafe { String::from_utf8_unchecked(buffer[pos..].to_vec()) }
    }

    #[inline(always)]
    pub fn base36_to_u64(s: &str) -> Result<u64, String> {
        if s.is_empty() {
            return Err("Empty string".to_string());
        }

        let bytes = s.as_bytes();

        // Fast path for common single digit case
        if bytes.len() == 1 {
            let digit = BASE36_DECODE[bytes[0] as usize];
            if digit == 255 {
                return Err(format!(
                    "Invalid character '{}' in base36 string",
                    bytes[0] as char
                ));
            }
            return Ok(digit as u64);
        }

        let mut result: u64 = 0;

        // Use lookup table for O(1) character to digit conversion
        for &byte in bytes {
            let digit = BASE36_DECODE[byte as usize];
            if digit == 255 {
                return Err(format!(
                    "Invalid character '{}' in base36 string",
                    byte as char
                ));
            }

            // Check for overflow using checked arithmetic
            result = match result
                .checked_mul(36)
                .and_then(|r| r.checked_add(digit as u64))
            {
                Some(val) => val,
                None => return Err("Overflow while parsing base36 string".to_string()),
            };
        }

        Ok(result)
    }
}

use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn benchmark_roundtrip(c: &mut Criterion) {
    c.bench_function("base36_roundtrip_small", |b| {
        b.iter(|| {
            // 0 to 1000 in steps of 1
            for i in (0..=1000).step_by(1) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }
        });
    });

    c.bench_function("base36_roundtrip_medium", |b| {
        b.iter(|| {
            // 1000 to 1_000_000 in steps of 100
            for i in (1000..=1_000_000).step_by(100) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }
        });
    });

    c.bench_function("base36_roundtrip_large", |b| {
        b.iter(|| {
            // 1_000_000 to 1_000_000_000 in steps of 10_000
            for i in (1_000_000..=1_000_000_000).step_by(10_000) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }
        });
    });

    c.bench_function("base36_roundtrip_combined", |b| {
        b.iter(|| {
            // Combined: all three ranges
            // 0 to 1000 in steps of 1
            for i in (0..=1000).step_by(1) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }

            // 1000 to 1_000_000 in steps of 100
            for i in (1000..=1_000_000).step_by(100) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }

            // 1_000_000 to 1_000_000_000 in steps of 10_000
            for i in (1_000_000..=1_000_000_000).step_by(10_000) {
                let encoded = base36_simple::u64_to_base36(black_box(i));
                let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
                black_box(decoded);
            }
        });
    });
}

criterion_group!(benches, benchmark_roundtrip);
criterion_main!(benches);

#[cfg(test)]
mod tests {

    #[test]
    fn test_u64_to_base36_specific_lines() {
        // Test lines 23-25 (value == 0 case)
        assert_eq!(base36_simple::u64_to_base36(0), "0");

        // Test line 30 (pos = 13)
        // Test lines 33-36 (while loop)
        assert_eq!(base36_simple::u64_to_base36(1), "1");
        assert_eq!(base36_simple::u64_to_base36(35), "z");
        assert_eq!(base36_simple::u64_to_base36(36), "10");
        assert_eq!(base36_simple::u64_to_base36(1296), "100");

        // Test line 40 (unsafe String::from_utf8_unchecked)
        assert_eq!(base36_simple::u64_to_base36(46656), "1000");
        assert_eq!(base36_simple::u64_to_base36(u64::MAX), "3w5e11264sgsf");
    }

    #[test]
    fn test_base36_to_u64_specific_lines() {
        // Test lines 44-46 (empty string case)
        match base36_simple::base36_to_u64("") {
            Err(msg) => assert_eq!(msg, "Empty string"),
            Ok(_) => panic!("Should have failed"),
        }

        // Test line 49 (get bytes)
        // Test lines 52-57 (single digit path and invalid character)
        assert_eq!(base36_simple::base36_to_u64("0").unwrap(), 0);
        assert_eq!(base36_simple::base36_to_u64("9").unwrap(), 9);
        assert_eq!(base36_simple::base36_to_u64("a").unwrap(), 10);
        assert_eq!(base36_simple::base36_to_u64("z").unwrap(), 35);

        // Test invalid single character (lines 54-57)
        match base36_simple::base36_to_u64("@") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }

        // Test line 60 (return Ok(digit as u64))
        assert_eq!(base36_simple::base36_to_u64("1").unwrap(), 1);
    }

    #[test]
    fn test_base36_to_u64_multi_digit_cases() {
        // Test line 63 (result = 0 initialization)
        // Test lines 66-71 (for loop with lookup table and invalid character)
        assert_eq!(base36_simple::base36_to_u64("10").unwrap(), 36);
        assert_eq!(base36_simple::base36_to_u64("zz").unwrap(), 1295);
        assert_eq!(base36_simple::base36_to_u64("100").unwrap(), 1296);

        // Test invalid character in multi-digit string (lines 68-71)
        match base36_simple::base36_to_u64("a@b") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }

        // Test lines 76-78 (checked_mul and checked_add)
        assert_eq!(base36_simple::base36_to_u64("abc").unwrap(), 13368); // 10*36*36 + 11*36 + 12

        // Test lines 80-81 (overflow case)
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz"; // Very long string to cause overflow
        match base36_simple::base36_to_u64(overflow_str) {
            Err(msg) => assert_eq!(msg, "Overflow while parsing base36 string"),
            Ok(_) => panic!("Should have failed"),
        }

        // Test line 85 (Ok(result))
        assert_eq!(base36_simple::base36_to_u64("123").unwrap(), 1371); // 1*36*36 + 2*36 + 3
    }

    #[test]
    fn test_roundtrip_comprehensive() {
        // Test roundtrip for various values to ensure all code paths work
        let test_values = vec![
            0,
            1,
            35,
            36,
            1295,
            1296,
            46655,
            46656,
            123456,
            987654321,
            u64::MAX,
        ];

        for value in test_values {
            let encoded = base36_simple::u64_to_base36(value);
            let decoded = base36_simple::base36_to_u64(&encoded).unwrap();
            assert_eq!(value, decoded, "Roundtrip failed for {}", value);
        }
    }

    #[test]
    fn test_edge_cases() {
        // Test maximum u64 value
        let max_encoded = base36_simple::u64_to_base36(u64::MAX);
        assert_eq!(max_encoded, "3w5e11264sgsf");
        assert_eq!(
            base36_simple::base36_to_u64(&max_encoded).unwrap(),
            u64::MAX
        );

        // Test various invalid inputs
        assert!(base36_simple::base36_to_u64("").is_err());
        assert!(base36_simple::base36_to_u64("@").is_err());
        assert!(base36_simple::base36_to_u64("123@").is_err());
        assert!(base36_simple::base36_to_u64("zzzzzzzzzzzzzzzzzzzz").is_err()); // Overflow
    }
}
