// Final benchmark comparing original vs ultra-optimized base36
const BASE36_CHARS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";

// Original simple implementation
#[inline(always)]
pub fn u64_to_base36_original(mut value: u64) -> String {
    if value == 0 {
        return "0".to_string();
    }
    
    let mut result = String::new();
    
    while value > 0 {
        let digit = (value % 36) as usize;
        result.insert(0, BASE36_CHARS[digit] as char);
        value /= 36;
    }
    
    result
}

#[inline(always)]
pub fn base36_to_u64_original(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)
}

// Ultra-optimized version (from our final implementation)
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_ultra(value: u64) -> String {
    // Specialized implementations for different ranges for maximum performance
    match value {
        0 => "0".to_string(),
        1..=35 => unsafe { String::from_utf8_unchecked(vec![BASE36_CHARS[value as usize]]) },
        36..=1295 => {
            let d1 = (value % 36) as usize;
            let d0 = (value / 36) as usize;
            unsafe { String::from_utf8_unchecked(vec![BASE36_CHARS[d0], BASE36_CHARS[d1]]) }
        }
        1296..=46655 => {
            let mut v = value;
            let d2 = (v % 36) as usize;
            v /= 36;
            let d1 = (v % 36) as usize;
            let d0 = (v / 36) as usize;
            unsafe {
                String::from_utf8_unchecked(vec![
                    BASE36_CHARS[d0],
                    BASE36_CHARS[d1],
                    BASE36_CHARS[d2],
                ])
            }
        }
        _ => {
            // General case for larger numbers
            let mut val = value;
            let mut buffer: [u8; 13] = [0; 13];
            let mut pos = 13;

            while val > 0 {
                pos -= 1;
                buffer[pos] = BASE36_CHARS[(val % 36) as usize];
                val /= 36;
            }

            unsafe { String::from_utf8_unchecked(buffer[pos..].to_vec()) }
        }
    }
}

#[inline(always)]
pub fn base36_to_u64_ultra(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;
    let mut i = 0;

    // Process 2 digits at a time when possible for better performance
    while i + 1 < bytes.len() {
        let d0 = BASE36_DECODE[bytes[i] as usize];
        let d1 = BASE36_DECODE[bytes[i + 1] as usize];

        if d0 == 255 || d1 == 255 {
            return Err("Invalid character in base36 string".to_string());
        }

        // result = result * 36^2 + d0 * 36 + d1
        result = match result
            .checked_mul(1296)
            .and_then(|r| r.checked_add((d0 as u64) * 36 + d1 as u64))
        {
            Some(val) => val,
            None => return Err("Overflow while parsing base36 string".to_string()),
        };

        i += 2;
    }

    // Handle remaining single digit
    if i < bytes.len() {
        let digit = BASE36_DECODE[bytes[i] as usize];
        if digit == 255 {
            return Err("Invalid character in base36 string".to_string());
        }

        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 std::time::Instant;

fn benchmark_final_comparison() {
    println!("Final Base36 Performance Comparison");
    println!("===================================");
    
    let iterations = 100;
    let test_ranges = [
        (0, 1000, 1),
        (1000, 1_000_000, 100),
        (1_000_000, 1_000_000_000, 10_000),
    ];
    
    println!("Testing encoding performance...");
    
    // Test original version
    let start = Instant::now();
    for _ in 0..iterations {
        for (start_val, end_val, step) in test_ranges {
            for i in (start_val..=end_val).step_by(step) {
                let encoded = u64_to_base36_original(i);
                std::hint::black_box(encoded);
            }
        }
    }
    let original_encode_time = start.elapsed();
    
    // Test ultra-optimized version
    let start = Instant::now();
    for _ in 0..iterations {
        for (start_val, end_val, step) in test_ranges {
            for i in (start_val..=end_val).step_by(step) {
                let encoded = u64_to_base36_ultra(i);
                std::hint::black_box(encoded);
            }
        }
    }
    let ultra_encode_time = start.elapsed();
    
    println!("Original encoding:      {:?}", original_encode_time);
    println!("Ultra-optimized:        {:?}", ultra_encode_time);
    println!("Encoding speedup:       {:.2}x", 
             original_encode_time.as_nanos() as f64 / ultra_encode_time.as_nanos() as f64);
    
    println!("\nTesting parsing performance...");
    
    // Generate test strings using ultra version (they're equivalent)
    let mut test_strings = Vec::new();
    for (start_val, end_val, step) in test_ranges {
        for i in (start_val..=end_val).step_by(step) {
            test_strings.push(u64_to_base36_ultra(i));
        }
    }
    
    // Test original parsing
    let start = Instant::now();
    for _ in 0..iterations {
        for s in &test_strings {
            let decoded = base36_to_u64_original(s).unwrap();
            std::hint::black_box(decoded);
        }
    }
    let original_parse_time = start.elapsed();
    
    // Test ultra-optimized parsing
    let start = Instant::now();
    for _ in 0..iterations {
        for s in &test_strings {
            let decoded = base36_to_u64_ultra(s).unwrap();
            std::hint::black_box(decoded);
        }
    }
    let ultra_parse_time = start.elapsed();
    
    println!("Original parsing:       {:?}", original_parse_time);
    println!("Ultra-optimized:        {:?}", ultra_parse_time);
    println!("Parsing speedup:        {:.2}x", 
             original_parse_time.as_nanos() as f64 / ultra_parse_time.as_nanos() as f64);
    
    // Combined roundtrip performance
    println!("\nTesting roundtrip performance...");
    
    let start = Instant::now();
    for _ in 0..iterations {
        for (start_val, end_val, step) in test_ranges {
            for i in (start_val..=end_val).step_by(step) {
                let encoded = u64_to_base36_original(i);
                let decoded = base36_to_u64_original(&encoded).unwrap();
                std::hint::black_box(decoded);
            }
        }
    }
    let original_roundtrip_time = start.elapsed();
    
    let start = Instant::now();
    for _ in 0..iterations {
        for (start_val, end_val, step) in test_ranges {
            for i in (start_val..=end_val).step_by(step) {
                let encoded = u64_to_base36_ultra(i);
                let decoded = base36_to_u64_ultra(&encoded).unwrap();
                std::hint::black_box(decoded);
            }
        }
    }
    let ultra_roundtrip_time = start.elapsed();
    
    println!("Original roundtrip:     {:?}", original_roundtrip_time);
    println!("Ultra-optimized:        {:?}", ultra_roundtrip_time);
    println!("Total speedup:          {:.2}x", 
             original_roundtrip_time.as_nanos() as f64 / ultra_roundtrip_time.as_nanos() as f64);
}

fn main() {
    // Verify correctness first
    println!("Verifying correctness...");
    for i in 0..10000 {
        let original = u64_to_base36_original(i);
        let ultra = u64_to_base36_ultra(i);
        assert_eq!(original, ultra, "Encoding mismatch at {}: {} vs {}", i, original, ultra);
        
        assert_eq!(base36_to_u64_original(&original).unwrap(), i);
        assert_eq!(base36_to_u64_ultra(&ultra).unwrap(), i);
    }
    println!("✅ Correctness verified for 10,000 values");
    println!();
    
    benchmark_final_comparison();
}

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

    #[test]
    fn test_u64_to_base36_original_specific_lines() {
        // Test lines 6-8 (value == 0 case)
        assert_eq!(u64_to_base36_original(0), "0");
        
        // Test line 11 (result = String::new())
        // Test lines 13-16 (while loop with insert)
        assert_eq!(u64_to_base36_original(1), "1");
        assert_eq!(u64_to_base36_original(35), "z");
        assert_eq!(u64_to_base36_original(36), "10");
        assert_eq!(u64_to_base36_original(1296), "100");
        
        // Test line 19 (return result)
        assert_eq!(u64_to_base36_original(46656), "1000");
        assert_eq!(u64_to_base36_original(u64::MAX), "3w5e11264sgsf");
    }

    #[test]
    fn test_base36_to_u64_original_specific_lines() {
        // Test lines 23-25 (empty string case)
        match base36_to_u64_original("") {
            Err(msg) => assert_eq!(msg, "Empty string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 28 (result initialization)
        // Test lines 30-34 (for loop with match)
        assert_eq!(base36_to_u64_original("0").unwrap(), 0);
        assert_eq!(base36_to_u64_original("9").unwrap(), 9);
        assert_eq!(base36_to_u64_original("a").unwrap(), 10);
        assert_eq!(base36_to_u64_original("z").unwrap(), 35);
        assert_eq!(base36_to_u64_original("10").unwrap(), 36);
        
        // Test invalid character (line 34)
        match base36_to_u64_original("@") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test lines 37-40 (checked arithmetic and overflow)
        assert_eq!(base36_to_u64_original("abc").unwrap(), 13368);
        
        // Test overflow case
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        match base36_to_u64_original(overflow_str) {
            Err(msg) => assert_eq!(msg, "Overflow while parsing base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 43 (Ok(result))
        assert_eq!(base36_to_u64_original("123").unwrap(), 1371);
    }

    #[test]
    fn test_u64_to_base36_ultra_specific_lines() {
        // Test line 63 (function start)
        // Test lines 65-71 (match arms for different ranges)
        assert_eq!(u64_to_base36_ultra(0), "0"); // 0 case
        assert_eq!(u64_to_base36_ultra(1), "1"); // 1..=35 case
        assert_eq!(u64_to_base36_ultra(35), "z"); // 1..=35 case
        assert_eq!(u64_to_base36_ultra(36), "10"); // 36..=1295 case
        assert_eq!(u64_to_base36_ultra(1295), "zz"); // 36..=1295 case
        
        // Test lines 73-78 (1296..=46655 case)
        assert_eq!(u64_to_base36_ultra(1296), "100");
        assert_eq!(u64_to_base36_ultra(46655), "zzz");
        
        // Test lines 80-83 (unsafe String::from_utf8_unchecked for 3 digits)
        assert_eq!(u64_to_base36_ultra(5000), "3uw");
        
        // Test line 87 (general case _)
        // Test lines 89-91 (buffer initialization)
        assert_eq!(u64_to_base36_ultra(46656), "1000");
        
        // Test lines 93-96 (while loop in general case)
        assert_eq!(u64_to_base36_ultra(1679616), "10000"); // 36^4
        
        // Test line 99 (unsafe String::from_utf8_unchecked for general case)
        assert_eq!(u64_to_base36_ultra(u64::MAX), "3w5e11264sgsf");
    }

    #[test]
    fn test_base36_to_u64_ultra_specific_lines() {
        // Test lines 105-107 (empty string case)
        match base36_to_u64_ultra("") {
            Err(msg) => assert_eq!(msg, "Empty string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 110 (get bytes)
        // Test lines 113-118 (single digit case)
        assert_eq!(base36_to_u64_ultra("0").unwrap(), 0);
        assert_eq!(base36_to_u64_ultra("9").unwrap(), 9);
        assert_eq!(base36_to_u64_ultra("a").unwrap(), 10);
        assert_eq!(base36_to_u64_ultra("z").unwrap(), 35);
        
        // Test invalid single character
        match base36_to_u64_ultra("@") {
            Err(msg) => assert!(msg.contains("Invalid character")),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 121 (return Ok(digit as u64))
        assert_eq!(base36_to_u64_ultra("1").unwrap(), 1);
        
        // Test lines 124-125 (result and i initialization)
        // Test lines 128-130 (while loop with two digit processing)
        assert_eq!(base36_to_u64_ultra("10").unwrap(), 36);
        assert_eq!(base36_to_u64_ultra("zz").unwrap(), 1295);
        
        // Test lines 132-133 (invalid character in two digit)
        match base36_to_u64_ultra("a@") {
            Err(msg) => assert_eq!(msg, "Invalid character in base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test lines 137-139 (checked arithmetic in two digit processing)
        assert_eq!(base36_to_u64_ultra("abc").unwrap(), 13368);
        
        // Test lines 141-142 (overflow in two digit processing)
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        match base36_to_u64_ultra(overflow_str) {
            Err(msg) => assert_eq!(msg, "Overflow while parsing base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test line 145 (i += 2)
        assert_eq!(base36_to_u64_ultra("1000").unwrap(), 46656);
        
        // Test lines 149-152 (remaining single digit handling)
        assert_eq!(base36_to_u64_ultra("abc1").unwrap(), 481249); // 13368 * 36 + 1
        
        // Test invalid remaining digit
        match base36_to_u64_ultra("ab@") {
            Err(msg) => assert_eq!(msg, "Invalid character in base36 string"),
            Ok(_) => panic!("Should have failed"),
        }
        
        // Test lines 155-157 (checked arithmetic for remaining digit)
        // Test lines 159-160 (overflow for remaining digit)
        assert_eq!(base36_to_u64_ultra("123").unwrap(), 1371);
        
        // Test line 164 (Ok(result))
        assert_eq!(base36_to_u64_ultra("test").unwrap(), 1372205);
    }

    #[test]
    fn test_roundtrip_original_vs_ultra() {
        // 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 original implementation roundtrip
            let original_encoded = u64_to_base36_original(value);
            let original_decoded = base36_to_u64_original(&original_encoded).unwrap();
            assert_eq!(original_decoded, value, "Original roundtrip failed for {}", value);
            
            // Test ultra implementation roundtrip
            let ultra_encoded = u64_to_base36_ultra(value);
            let ultra_decoded = base36_to_u64_ultra(&ultra_encoded).unwrap();
            assert_eq!(ultra_decoded, value, "Ultra roundtrip failed for {}", value);
            
            // Test that both implementations produce the same result
            assert_eq!(original_encoded, ultra_encoded, "Implementations disagree for {}", value);
        }
    }

    #[test]
    fn test_edge_cases_both_implementations() {
        // Test edge cases for maximum values
        let max_encoded_original = u64_to_base36_original(u64::MAX);
        let max_encoded_ultra = u64_to_base36_ultra(u64::MAX);
        assert_eq!(max_encoded_original, "3w5e11264sgsf");
        assert_eq!(max_encoded_ultra, "3w5e11264sgsf");
        assert_eq!(max_encoded_original, max_encoded_ultra);
        
        // Test parsing of max value
        assert_eq!(base36_to_u64_original(&max_encoded_original).unwrap(), u64::MAX);
        assert_eq!(base36_to_u64_ultra(&max_encoded_ultra).unwrap(), u64::MAX);
        
        // Test boundary values for ultra implementation ranges
        assert_eq!(u64_to_base36_ultra(35), "z"); // Last single digit
        assert_eq!(u64_to_base36_ultra(36), "10"); // First two digit
        assert_eq!(u64_to_base36_ultra(1295), "zz"); // Last two digit
        assert_eq!(u64_to_base36_ultra(1296), "100"); // First three digit
        assert_eq!(u64_to_base36_ultra(46655), "zzz"); // Last three digit
        assert_eq!(u64_to_base36_ultra(46656), "1000"); // First general case
    }

    #[test]
    fn test_error_cases_both_implementations() {
        // Test empty string
        assert!(base36_to_u64_original("").is_err());
        assert!(base36_to_u64_ultra("").is_err());
        
        // Test invalid characters
        assert!(base36_to_u64_original("@").is_err());
        assert!(base36_to_u64_ultra("@").is_err());
        assert!(base36_to_u64_original("abc@").is_err());
        assert!(base36_to_u64_ultra("abc@").is_err());
        
        // Test overflow
        let overflow_str = "zzzzzzzzzzzzzzzzzzzz";
        assert!(base36_to_u64_original(overflow_str).is_err());
        assert!(base36_to_u64_ultra(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_original(value), expected);
            assert_eq!(u64_to_base36_ultra(value), expected);
            assert_eq!(base36_to_u64_original(expected).unwrap(), value);
            assert_eq!(base36_to_u64_ultra(expected).unwrap(), value);
        }
    }
}