// Standalone benchmark that doesn't depend on anything else
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_optimized(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_optimized(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)
}

// Original simple implementation for comparison
#[inline(always)]
pub fn u64_to_base36_simple(mut value: u64) -> String {
    if value == 0 {
        return "0".to_string();
    }
    
    let mut result = Vec::new();
    
    while value > 0 {
        let digit = (value % 36) as usize;
        result.push(BASE36_CHARS[digit]);
        value /= 36;
    }
    
    result.reverse();
    String::from_utf8(result).unwrap()
}

#[inline(always)]
pub fn base36_to_u64_simple(s: &str) -> Result<u64, String> {
    if s.is_empty() {
        return Err("Empty string".to_string());
    }
    
    let mut result: u64 = 0;
    
    for c in s.chars() {
        let digit = match c {
            '0'..='9' => c as u64 - '0' as u64,
            'a'..='z' => c as u64 - 'a' as u64 + 10,
            _ => return Err(format!("Invalid character '{}' in base36 string", c)),
        };
        
        result = result
            .checked_mul(36)
            .and_then(|r| r.checked_add(digit))
            .ok_or_else(|| "Overflow while parsing base36 string".to_string())?;
    }
    
    Ok(result)
}

use std::time::Instant;

fn benchmark_roundtrip() {
    println!("Running base36 roundtrip benchmarks...");
    println!("======================================");
    
    // Benchmark optimized version
    let start = Instant::now();
    for _ in 0..100 {
        // 0 to 1000 in steps of 1
        for i in (0..=1000).step_by(1) {
            let encoded = u64_to_base36_optimized(i);
            let decoded = base36_to_u64_optimized(&encoded).unwrap();
            std::hint::black_box(decoded);
        }
        
        // 1000 to 1_000_000 in steps of 100
        for i in (1000..=1_000_000).step_by(100) {
            let encoded = u64_to_base36_optimized(i);
            let decoded = base36_to_u64_optimized(&encoded).unwrap();
            std::hint::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 = u64_to_base36_optimized(i);
            let decoded = base36_to_u64_optimized(&encoded).unwrap();
            std::hint::black_box(decoded);
        }
    }
    let optimized_time = start.elapsed();
    
    // Benchmark simple version
    let start = Instant::now();
    for _ in 0..100 {
        // 0 to 1000 in steps of 1
        for i in (0..=1000).step_by(1) {
            let encoded = u64_to_base36_simple(i);
            let decoded = base36_to_u64_simple(&encoded).unwrap();
            std::hint::black_box(decoded);
        }
        
        // 1000 to 1_000_000 in steps of 100
        for i in (1000..=1_000_000).step_by(100) {
            let encoded = u64_to_base36_simple(i);
            let decoded = base36_to_u64_simple(&encoded).unwrap();
            std::hint::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 = u64_to_base36_simple(i);
            let decoded = base36_to_u64_simple(&encoded).unwrap();
            std::hint::black_box(decoded);
        }
    }
    let simple_time = start.elapsed();
    
    println!("Optimized version: {:?}", optimized_time);
    println!("Simple version:    {:?}", simple_time);
    println!("Speedup:           {:.2}x", simple_time.as_nanos() as f64 / optimized_time.as_nanos() as f64);
}

fn main() {
    // Verify correctness first
    for i in 0..10000 {
        let opt = u64_to_base36_optimized(i);
        let simple = u64_to_base36_simple(i);
        assert_eq!(opt, simple, "Mismatch at {}: {} vs {}", i, opt, simple);
        
        assert_eq!(base36_to_u64_optimized(&opt).unwrap(), i);
        assert_eq!(base36_to_u64_simple(&simple).unwrap(), i);
    }
    
    println!("✅ Correctness verified for 10,000 values");
    println!();
    
    benchmark_roundtrip();
}

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

    #[test]
    fn test_u64_to_base36_optimized_specific_lines() {
        // Test lines 21-23 (value == 0 case)
        assert_eq!(u64_to_base36_optimized(0), "0");
        
        // Test line 28 (pos = 13)
        // Test lines 31-34 (while loop)
        assert_eq!(u64_to_base36_optimized(1), "1");
        assert_eq!(u64_to_base36_optimized(35), "z");
        assert_eq!(u64_to_base36_optimized(36), "10");
        assert_eq!(u64_to_base36_optimized(1296), "100");
        
        // Test line 38 (unsafe String::from_utf8_unchecked)
        assert_eq!(u64_to_base36_optimized(46656), "1000");
        assert_eq!(u64_to_base36_optimized(u64::MAX), "3w5e11264sgsf");
    }

    #[test]
    fn test_base36_to_u64_optimized_specific_lines() {
        // Test lines 42-44 (empty string case)
        match base36_to_u64_optimized("") {
            Err(msg) => assert_eq!(msg, "Empty string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 47 (get bytes)
        // Test lines 50-53 (single digit case)
        assert_eq!(base36_to_u64_optimized("0").unwrap(), 0);
        assert_eq!(base36_to_u64_optimized("9").unwrap(), 9);
        assert_eq!(base36_to_u64_optimized("a").unwrap(), 10);
        assert_eq!(base36_to_u64_optimized("z").unwrap(), 35);
        
        // Test invalid single character
        match base36_to_u64_optimized("@") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 55 (return Ok(digit as u64))
        assert_eq!(base36_to_u64_optimized("1").unwrap(), 1);
        
        // Test line 58 (result initialization)
        // Test lines 61-64 (for loop with lookup table and invalid character)
        assert_eq!(base36_to_u64_optimized("10").unwrap(), 36);
        assert_eq!(base36_to_u64_optimized("zz").unwrap(), 1295);
        
        // Test invalid character in multi-digit string
        match base36_to_u64_optimized("a@b") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test lines 68-70 (checked arithmetic and overflow)
        assert_eq!(base36_to_u64_optimized("abc").unwrap(), 13368);
        
        // Test overflow case
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        match base36_to_u64_optimized(overflow_str) {
            Err(msg) => assert_eq!(msg, "Overflow while parsing base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 74 (Ok(result))
        assert_eq!(base36_to_u64_optimized("123").unwrap(), 1371);
    }

    #[test]
    fn test_u64_to_base36_simple_specific_lines() {
        // Test lines 79-81 (value == 0 case)
        assert_eq!(u64_to_base36_simple(0), "0");
        
        // Test line 84 (result Vec initialization)
        // Test lines 86-89 (while loop with push)
        assert_eq!(u64_to_base36_simple(1), "1");
        assert_eq!(u64_to_base36_simple(35), "z");
        assert_eq!(u64_to_base36_simple(36), "10");
        assert_eq!(u64_to_base36_simple(1296), "100");
        
        // Test lines 92-93 (reverse and String::from_utf8)
        assert_eq!(u64_to_base36_simple(46656), "1000");
        assert_eq!(u64_to_base36_simple(u64::MAX), "3w5e11264sgsf");
    }

    #[test]
    fn test_base36_to_u64_simple_specific_lines() {
        // Test lines 97-99 (empty string case)
        match base36_to_u64_simple("") {
            Err(msg) => assert_eq!(msg, "Empty string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 102 (result initialization)
        // Test lines 104-108 (for loop with match)
        assert_eq!(base36_to_u64_simple("0").unwrap(), 0);
        assert_eq!(base36_to_u64_simple("9").unwrap(), 9);
        assert_eq!(base36_to_u64_simple("a").unwrap(), 10);
        assert_eq!(base36_to_u64_simple("z").unwrap(), 35);
        assert_eq!(base36_to_u64_simple("10").unwrap(), 36);
        
        // Test invalid character (line 108)
        match base36_to_u64_simple("@") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test lines 111-114 (checked arithmetic and overflow)
        assert_eq!(base36_to_u64_simple("abc").unwrap(), 13368);
        
        // Test overflow case
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        match base36_to_u64_simple(overflow_str) {
            Err(msg) => assert_eq!(msg, "Overflow while parsing base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 117 (Ok(result))
        assert_eq!(base36_to_u64_simple("123").unwrap(), 1371);
    }

    #[test]
    fn test_roundtrip_optimized_vs_simple() {
        // Test roundtrip for both implementations
        let test_values = vec![
            0, 1, 35, 36, 1295, 1296, 46655, 46656,
            123456, 987654321, u64::MAX / 2, u64::MAX
        ];

        for value in test_values {
            // Test optimized implementation roundtrip
            let optimized_encoded = u64_to_base36_optimized(value);
            let optimized_decoded = base36_to_u64_optimized(&optimized_encoded).unwrap();
            assert_eq!(optimized_decoded, value, "Optimized roundtrip failed for {}", value);
            
            // Test simple implementation roundtrip
            let simple_encoded = u64_to_base36_simple(value);
            let simple_decoded = base36_to_u64_simple(&simple_encoded).unwrap();
            assert_eq!(simple_decoded, value, "Simple roundtrip failed for {}", value);
            
            // Test that both implementations produce the same result
            assert_eq!(optimized_encoded, simple_encoded, "Implementations disagree for {}", value);
        }
    }

    #[test]
    fn test_edge_cases_both_implementations() {
        // Test edge cases for maximum values
        let max_encoded_optimized = u64_to_base36_optimized(u64::MAX);
        let max_encoded_simple = u64_to_base36_simple(u64::MAX);
        assert_eq!(max_encoded_optimized, "3w5e11264sgsf");
        assert_eq!(max_encoded_simple, "3w5e11264sgsf");
        assert_eq!(max_encoded_optimized, max_encoded_simple);
        
        // Test parsing of max value
        assert_eq!(base36_to_u64_optimized(&max_encoded_optimized).unwrap(), u64::MAX);
        assert_eq!(base36_to_u64_simple(&max_encoded_simple).unwrap(), u64::MAX);
    }

    #[test]
    fn test_error_cases_both_implementations() {
        // Test empty string
        assert!(base36_to_u64_optimized("").is_err());
        assert!(base36_to_u64_simple("").is_err());
        
        // Test invalid characters
        assert!(base36_to_u64_optimized("@").is_err());
        assert!(base36_to_u64_simple("@").is_err());
        assert!(base36_to_u64_optimized("abc@").is_err());
        assert!(base36_to_u64_simple("abc@").is_err());
        
        // Test overflow
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        assert!(base36_to_u64_optimized(overflow_str).is_err());
        assert!(base36_to_u64_simple(overflow_str).is_err());
    }

    #[test]
    fn test_special_values() {
        // Test some special mathematical values
        let test_cases = vec![
            (0, "0"),
            (36, "10"),
            (36*36, "100"),
            (36*36*36, "1000"),
            (36*36*36*36, "10000"),
        ];

        for (value, expected) in test_cases {
            assert_eq!(u64_to_base36_optimized(value), expected);
            assert_eq!(u64_to_base36_simple(value), expected);
            assert_eq!(base36_to_u64_optimized(expected).unwrap(), value);
            assert_eq!(base36_to_u64_simple(expected).unwrap(), value);
        }
    }

    #[test]
    fn test_performance_critical_paths() {
        // Test paths that are performance-critical in both implementations
        
        // Test single digit values (common case)
        for i in 0..36 {
            let optimized = u64_to_base36_optimized(i);
            let simple = u64_to_base36_simple(i);
            assert_eq!(optimized, simple);
            
            assert_eq!(base36_to_u64_optimized(&optimized).unwrap(), i);
            assert_eq!(base36_to_u64_simple(&simple).unwrap(), i);
        }
        
        // Test two digit values
        for i in 36..1296 {
            let optimized = u64_to_base36_optimized(i);
            let simple = u64_to_base36_simple(i);
            assert_eq!(optimized, simple);
        }
        
        // Test three digit values (sample)
        let three_digit_samples = [1296, 2000, 10000, 46655];
        for &i in &three_digit_samples {
            let optimized = u64_to_base36_optimized(i);
            let simple = u64_to_base36_simple(i);
            assert_eq!(optimized, simple);
            
            assert_eq!(base36_to_u64_optimized(&optimized).unwrap(), i);
            assert_eq!(base36_to_u64_simple(&simple).unwrap(), i);
        }
    }
}