///all ctf utils functions, activate feature by `cargo add doe -F ctf`
#[allow(warnings)]
#[cfg(feature = "ctf")]
pub mod ctf {
    pub use ctf_party::*;
    ///
    ///
    /// ```ignore
    ///use doe::ctf::{CtfParty, Base64Mode, BitNumbering, HexCase, Nibble, EmailMode, FlagConfig};
    ///
    ///fn main() {
    ///    println!("=== CTF Party Trait Demonstration ===\n");
    ///
    ///    // Base64 examples
    ///    println!("--- Base64 Encoding/Decoding ---");
    ///    let text = "Hello, World!";
    ///    println!("Original: {}", text);
    ///    println!("Base64 encoded: {}", text.to_b64(Base64Mode::Strict));
    ///    println!("Is valid base64? {}", "SGVsbG8sIFdvcmxkIQ==".is_b64(Base64Mode::Strict));
    ///    println!();
    ///
    ///    // Binary encoding
    ///    println!("--- Binary Encoding ---");
    ///    println!("'AB' to binary (MSB): {}", "AB".to_bin(BitNumbering::MSB));
    ///    println!("'0100000101000010' from binary: {:?}", "0100000101000010".from_bin(BitNumbering::MSB));
    ///    println!();
    ///
    ///    // Case modifications
    ///    println!("--- Case Modifications ---");
    ///    println!("Random case: {}", "hello world".randomcase());
    ///    println!("Alternate case: {}", "hello world".alternatecase(0));
    ///    println!();
    ///
    ///    // URL encoding
    ///    println!("--- URL Encoding ---");
    ///    let url = "http://example.com/search?q=hello world";
    ///    println!("URL encode: {}", url.urlencode_data());
    ///    println!("URL decode: {:?}", "%3Cscript%3E".urldecode_data());
    ///    println!();
    ///
    ///    // Hash functions
    ///    println!("--- Hash Functions ---");
    ///    println!("MD5 of 'hello': {}", "hello".md5());
    ///    println!("SHA1 of 'hello': {}", "hello".sha1());
    ///    println!("SHA2-256 of 'hello': {}", "hello".sha2_256());
    ///    println!();
    ///
    ///    // Hexadecimal operations
    ///    println!("--- Hexadecimal Operations ---");
    ///    println!("'hello' to hex: {}", "hello".to_hex("", "", HexCase::Lower, Nibble::High));
    ///    println!("'68656c6c6f' from hex: {:?}", "68656c6c6f".from_hex("", Nibble::High));
    ///    println!("255 dec to hex: {}", "255".dec2hex("", "", HexCase::Lower, 2));
    ///    println!("ff hex to dec: {:?}", "ff".hex2dec("", 0));
    ///    println!();
    ///
    ///    // IP operations
    ///    println!("--- IP Operations ---");
    ///    println!("Defang IP: {}", "192.168.1.1".defang_ip(false));
    ///    println!("Refang IP: {}", "192[.]168[.]1[.]1".refang_ip(false));
    ///    println!("127.0.0.1 to hex IPv4: {}", "127.0.0.1".to_hexipv4("", "", HexCase::Lower, Nibble::High));
    ///    println!();
    ///
    ///    // ROT cipher
    ///    println!("--- ROT Cipher ---");
    ///    println!("ROT13: {}", "Hello, World!".rot(13));
    ///    println!("ROT5: {}", "Hello, World!".rot(5));
    ///    println!();
    ///
    ///    // XOR operations
    ///    println!("--- XOR Operations ---");
    ///    println!("UTF-8 XOR 'hello' ^ 'key': {:?}", "hello".ulxor("key"));
    ///    println!("ASCII XOR 'hello' ^ 'key': {:?}", "hello".alxor("key"));
    ///    println!();
    ///
    ///    // Validation
    ///    println!("--- Validation ---");
    ///    println!("Is '192.168.1.1' IPv4? {}", "192.168.1.1".is_ipv4());
    ///    println!("Is 'example.com' a domain? {}", "example.com".is_domain());
    ///    println!("Is 'test@example.com' an email? {}", "test@example.com".is_email(EmailMode::Light));
    ///    println!();
    ///
    ///    // Flag formatting
    ///    println!("--- Flag Formatting ---");
    ///    let flag_config = FlagConfig {
    ///        prefix: "flag".to_string(),
    ///        suffix: String::new(),
    ///        enclosing: ('{', '}'),
    ///        digest: None,
    ///    };
    ///    println!("Flag: {}", "test_flag".flag(&flag_config));
    ///    println!("Is flag? {}", "flag{test_flag}".is_flag(&flag_config));
    ///    println!();
    ///
    ///    // Leet speak
    ///    println!("--- Leet Speak ---");
    ///    println!("'The quick brown fox' in leet: {}", "The quick brown fox".leet());
    ///    println!();
    ///
    ///    // String operations
    ///    println!("--- String Operations ---");
    ///    println!("Strip whitespace: {}", "  hello   world  ".istrip());
    ///    println!();
    ///
    ///    println!("=== Demonstration Complete ===");
    ///}
    /// ```
    ///
    pub mod ctf_party {
        // CTF Party Trait - Rust implementation of Ruby ctf_party library
        // Provides various encoding, decoding, and transformation functions

        use base64::{engine::general_purpose, Engine as _};
        use digest::Digest;
        use md5::compute;
        use regex::Regex;
        use ripemd::Ripemd160 as Ripemd160Digest;
        use sha1::Sha1;
        use sha2::{Sha256, Sha384, Sha512};
        use std::net::{Ipv4Addr, Ipv6Addr};
        use url::Url;

        pub trait CtfParty {
            // Base64 encoding/decoding
            fn to_b64(&self, mode: Base64Mode) -> String;
            fn from_b64(&self, mode: Base64Mode) -> Result<String, String>;
            fn is_b64(&self, mode: Base64Mode) -> bool;

            // Binary encoding/decoding
            fn to_bin(&self, bitnumbering: BitNumbering) -> String;
            fn from_bin(&self, bitnumbering: BitNumbering) -> Result<String, String>;
            fn bin2dec(&self) -> Result<String, String>;
            fn dec2bin(&self) -> Result<String, String>;

            // Case modifications
            fn randomcase(&self) -> String;
            fn alternatecase(&self, shift: usize) -> String;

            // URL encoding/decoding
            fn urlencode(&self) -> String;
            fn urldecode(&self) -> Result<String, String>;
            fn urlencode_data(&self) -> String;
            fn urldecode_data(&self) -> Result<String, String>;
            fn htmlescape(&self) -> String;
            fn htmlunescape(&self) -> String;
            fn urlencode_component(&self) -> String;
            fn urldecode_component(&self) -> Result<String, String>;

            // Decimal encoding/decoding
            fn to_dec(&self) -> String;
            fn from_dec(&self) -> Result<String, String>;

            // IP/URI/Domain/Email defanging/refanging
            fn defang_ip(&self, unvalid: bool) -> String;
            fn refang_ip(&self, unvalid: bool) -> String;
            fn defang_uri(&self) -> String;
            fn refang_uri(&self) -> Result<String, String>;
            fn defang_domain(&self, unvalid: bool) -> String;
            fn refang_domain(&self, unvalid: bool) -> String;
            fn defang_email(&self, unvalid: bool) -> String;
            fn refang_email(&self, unvalid: bool) -> String;

            // Hash functions
            fn md5(&self) -> String;
            fn sha1(&self) -> String;
            fn sha2_256(&self) -> String;
            fn sha2_384(&self) -> String;
            fn sha2_512(&self) -> String;
            fn rmd160(&self) -> String;

            // Flag formatting
            fn flag(&self, config: &FlagConfig) -> String;
            fn is_flag(&self, config: &FlagConfig) -> bool;

            // Hexadecimal encoding/decoding
            fn hex2dec(&self, prefix: &str, padding: usize) -> Result<String, String>;
            fn dec2hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                padding: usize,
            ) -> String;
            fn to_hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String;
            fn from_hex(&self, prefix: &str, nibble: Nibble) -> Result<String, String>;
            fn hex2bin(&self, prefix: &str, even: bool) -> Result<String, String>;
            fn bin2hex(&self, prefix: &str, prefixall: &str, case: HexCase) -> String;
            fn from_hexipv4(&self, prefix: &str, nibble: Nibble) -> Result<String, String>;
            fn from_hexipv6(&self, prefix: &str) -> Result<String, String>;
            fn to_hexipv4(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String;

            // Leet speak
            fn leet(&self) -> String;

            // String stripping
            fn istrip(&self) -> String;

            // Validation
            fn is_ipv4(&self) -> bool;
            fn is_ipv6(&self) -> bool;
            fn is_ip(&self) -> bool;
            fn is_uri(&self, lax: bool) -> bool;
            fn is_domain(&self) -> bool;
            fn is_email(&self, mode: EmailMode) -> bool;

            // ROT cipher
            fn rot(&self, shift: i32) -> String;
            fn rot_all(&self) -> Vec<(i32, String)>;

            // XOR operations
            fn ulxor(&self, key: &str) -> String;
            fn alxor(&self, key: &str) -> Result<String, String>;
            fn urxor(&self, key: &str) -> String;
            fn arxor(&self, key: &str) -> Result<String, String>;
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum Base64Mode {
            Strict,
            Rfc2045,
            UrlSafe,
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum BitNumbering {
            MSB,
            LSB,
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum HexCase {
            Lower,
            Upper,
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum Nibble {
            High,
            Low,
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum EmailMode {
            Rfc5322,
            Light,
            LightWithLength,
        }

        #[derive(Debug, Clone)]
        pub struct FlagConfig {
            pub prefix: String,
            pub suffix: String,
            pub enclosing: (char, char),
            pub digest: Option<DigestType>,
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum DigestType {
            Md5,
            Sha1,
            Sha2_256,
            Sha2_384,
            Sha2_512,
            Rmd160,
        }

        impl Default for FlagConfig {
            fn default() -> Self {
                Self {
                    prefix: String::new(),
                    suffix: String::new(),
                    enclosing: ('{', '}'),
                    digest: None,
                }
            }
        }

        // Helper function removed (was unused)

        impl CtfParty for str {
            // Base64 encoding
            fn to_b64(&self, mode: Base64Mode) -> String {
                match mode {
                    Base64Mode::Strict => general_purpose::STANDARD.encode(self),
                    Base64Mode::Rfc2045 => {
                        // Add line breaks every 76 chars
                        let encoded = general_purpose::STANDARD.encode(self);
                        encoded
                            .chars()
                            .collect::<Vec<char>>()
                            .chunks(76)
                            .map(|c| c.iter().collect::<String>())
                            .collect::<Vec<_>>()
                            .join("\n")
                    }
                    Base64Mode::UrlSafe => general_purpose::URL_SAFE.encode(self),
                }
            }

            fn from_b64(&self, mode: Base64Mode) -> Result<String, String> {
                let result = match mode {
                    Base64Mode::Strict => general_purpose::STANDARD.decode(self),
                    Base64Mode::Rfc2045 => {
                        let cleaned = self.replace('\n', "").replace('\r', "");
                        general_purpose::STANDARD.decode(&cleaned)
                    }
                    Base64Mode::UrlSafe => general_purpose::URL_SAFE.decode(self),
                };

                result
                    .map(|bytes| String::from_utf8(bytes).unwrap_or_default())
                    .map_err(|e| e.to_string())
            }

            fn is_b64(&self, mode: Base64Mode) -> bool {
                let test_str = match mode {
                    Base64Mode::Strict => self,
                    Base64Mode::Rfc2045 => self, // Will test each line
                    Base64Mode::UrlSafe => self,
                };

                let strict_regex = Regex::new(
            r"^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$"
        ).unwrap();

                let urlsafe_regex = Regex::new(
            r"^(?:[a-zA-Z0-9\-_]{4})*(?:|(?:[a-zA-Z0-9\-_]{3}=)|(?:[a-zA-Z0-9\-_]{2}==)|(?:[a-zA-Z0-9\-_]{1}===))$"
        ).unwrap();

                match mode {
                    Base64Mode::Strict => strict_regex.is_match(test_str),
                    Base64Mode::Rfc2045 => test_str.lines().all(|line| strict_regex.is_match(line)),
                    Base64Mode::UrlSafe => urlsafe_regex.is_match(test_str),
                }
            }

            // Binary encoding/decoding
            fn to_bin(&self, bitnumbering: BitNumbering) -> String {
                match bitnumbering {
                    BitNumbering::MSB => self
                        .bytes()
                        .flat_map(|b| (0..8).rev().map(move |i| (b >> i) & 1))
                        .map(|b| if b == 1 { '1' } else { '0' })
                        .collect(),
                    BitNumbering::LSB => self
                        .bytes()
                        .flat_map(|b| (0..8).map(move |i| (b >> i) & 1))
                        .map(|b| if b == 1 { '1' } else { '0' })
                        .collect(),
                }
            }

            fn from_bin(&self, bitnumbering: BitNumbering) -> Result<String, String> {
                if self.chars().any(|c| c != '0' && c != '1') {
                    return Err("Invalid binary string".to_string());
                }

                if self.len() % 8 != 0 {
                    return Err("Binary string length must be multiple of 8".to_string());
                }

                let bytes: Vec<u8> = self
                    .as_bytes()
                    .chunks(8)
                    .map(|chunk| {
                        let chunk_str = std::str::from_utf8(chunk).unwrap();
                        match bitnumbering {
                            BitNumbering::MSB => u8::from_str_radix(chunk_str, 2).unwrap(),
                            BitNumbering::LSB => chunk_str
                                .chars()
                                .enumerate()
                                .fold(0u8, |acc, (i, c)| acc | ((c as u8 - b'0') << i)),
                        }
                    })
                    .collect();

                String::from_utf8(bytes).map_err(|e| e.to_string())
            }

            fn bin2dec(&self) -> Result<String, String> {
                let hex = CtfParty::bin2hex(self, "", "", HexCase::Lower);
                CtfParty::hex2dec(&hex, "", 0)
            }

            fn dec2bin(&self) -> Result<String, String> {
                let hex = CtfParty::dec2hex(self, "", "", HexCase::Lower, 2);
                CtfParty::hex2bin(&hex, "", true)
            }

            // Case modifications
            fn randomcase(&self) -> String {
                use std::collections::hash_map::DefaultHasher;
                use std::hash::{Hash, Hasher};

                self.chars()
                    .enumerate()
                    .map(|(i, c)| {
                        let mut hasher = DefaultHasher::new();
                        i.hash(&mut hasher);
                        if hasher.finish() % 2 == 0 {
                            c.to_lowercase().collect::<String>()
                        } else {
                            c.to_uppercase().collect::<String>()
                        }
                    })
                    .collect()
            }

            fn alternatecase(&self, shift: usize) -> String {
                self.chars()
                    .enumerate()
                    .map(|(i, c)| {
                        if (i + shift) % 2 == 0 {
                            c.to_lowercase().collect::<String>()
                        } else {
                            c.to_uppercase().collect::<String>()
                        }
                    })
                    .collect()
            }

            // URL encoding/decoding
            fn urlencode(&self) -> String {
                percent_encoding::utf8_percent_encode(self, percent_encoding::CONTROLS).collect()
            }

            fn urldecode(&self) -> Result<String, String> {
                percent_encoding::percent_decode_str(self)
                    .decode_utf8()
                    .map(|s| s.to_string())
                    .map_err(|e| e.to_string())
            }

            fn urlencode_data(&self) -> String {
                percent_encoding::utf8_percent_encode(self, percent_encoding::NON_ALPHANUMERIC)
                    .to_string()
            }

            fn urldecode_data(&self) -> Result<String, String> {
                percent_encoding::percent_decode_str(self)
                    .decode_utf8()
                    .map(|s| s.to_string())
                    .map_err(|e| e.to_string())
            }

            fn htmlescape(&self) -> String {
                self.replace('&', "&amp;")
                    .replace('<', "&lt;")
                    .replace('>', "&gt;")
                    .replace('"', "&quot;")
                    .replace('\'', "&#39;")
            }

            fn htmlunescape(&self) -> String {
                self.replace("&amp;", "&")
                    .replace("&lt;", "<")
                    .replace("&gt;", ">")
                    .replace("&quot;", "\"")
                    .replace("&#39;", "'")
                    .replace("&apos;", "'")
            }

            fn urlencode_component(&self) -> String {
                percent_encoding::utf8_percent_encode(self, percent_encoding::NON_ALPHANUMERIC)
                    .to_string()
            }

            fn urldecode_component(&self) -> Result<String, String> {
                percent_encoding::percent_decode_str(self)
                    .decode_utf8()
                    .map(|s| s.to_string())
                    .map_err(|e| e.to_string())
            }

            // Decimal encoding/decoding
            fn to_dec(&self) -> String {
                let hex = CtfParty::to_hex(self, "", "", HexCase::Lower, Nibble::High);
                CtfParty::hex2dec(&hex, "", 0).unwrap_or_default()
            }

            fn from_dec(&self) -> Result<String, String> {
                let hex = CtfParty::dec2hex(self, "", "", HexCase::Lower, 2);
                CtfParty::from_hex(&hex, "", Nibble::High)
            }

            // IP/URI/Domain/Email defanging/refanging
            fn defang_ip(&self, unvalid: bool) -> String {
                if CtfParty::is_ipv4(self) {
                    self.replace('.', "[.]")
                } else if CtfParty::is_ipv6(self) {
                    self.replace(':', "[:]")
                } else if unvalid {
                    self.replace('.', "[.]").replace(':', "[:]")
                } else {
                    self.to_string()
                }
            }

            fn refang_ip(&self, unvalid: bool) -> String {
                let re_ipv4 = self.replace("[.]", ".");
                let re_ipv6 = self.replace("[:]", ":");

                if CtfParty::is_ipv4(&re_ipv4) {
                    re_ipv4
                } else if CtfParty::is_ipv6(&re_ipv6) {
                    re_ipv6
                } else if unvalid {
                    self.replace("[.]", ".").replace("[:]", ":")
                } else {
                    self.to_string()
                }
            }

            fn defang_uri(&self) -> String {
                if let Ok(uri) = Url::parse(self) {
                    let scheme = uri.scheme();
                    let defanged_scheme = match scheme {
                        "http" | "https" | "ftp" => scheme.replace('t', "x"),
                        "ws" | "wss" => {
                            let mut chars = scheme.chars().collect::<Vec<_>>();
                            chars.insert(1, 'x');
                            chars.into_iter().collect()
                        }
                        "ldap" | "ldaps" => {
                            let mut chars = scheme.chars().collect::<Vec<_>>();
                            chars.insert(2, 'x');
                            chars.into_iter().collect()
                        }
                        "mailto" => {
                            let mut chars = scheme.chars().collect::<Vec<_>>();
                            chars.insert(4, 'x');
                            return uri.to_string().replace('.', "[.]").replace('@', "[@]");
                        }
                        _ => scheme.to_string(),
                    };

                    uri.to_string()
                        .replacen(scheme, &defanged_scheme, 1)
                        .replace('.', "[.]")
                } else {
                    self.replace('.', "[.]")
                }
            }

            fn refang_uri(&self) -> Result<String, String> {
                // Handle schemes
                if self.contains("://") {
                    let parts: Vec<&str> = self.splitn(2, "://").collect();
                    if parts.len() == 2 {
                        let scheme = parts[0];
                        let remains = parts[1];

                        let fixed_scheme = scheme
                            .replace("hxxp", "http")
                            .replace("hxxps", "https")
                            .replace("fxp", "ftp")
                            .replace("wxss", "wss")
                            .replace("wxs", "ws")
                            .replace("ldxaps", "ldaps")
                            .replace("ldxap", "ldap")
                            .replace("mailxto", "mailto");

                        let fixed_remains = remains.replace("[.]", ".");

                        return Ok(format!("{}://{}", fixed_scheme, fixed_remains));
                    }
                }

                let result = self.replace("[.]", ".");
                Ok(result)
            }

            fn defang_domain(&self, unvalid: bool) -> String {
                if CtfParty::is_domain(self) || unvalid {
                    self.replace('.', "[.]")
                } else {
                    self.to_string()
                }
            }

            fn refang_domain(&self, unvalid: bool) -> String {
                let re_domain = self.replace("[.]", ".");
                if CtfParty::is_domain(&re_domain) || unvalid {
                    re_domain
                } else {
                    self.to_string()
                }
            }

            fn defang_email(&self, unvalid: bool) -> String {
                if CtfParty::is_email(self, EmailMode::Light) || unvalid {
                    self.replace('.', "[.]").replace('@', "[@]")
                } else {
                    self.to_string()
                }
            }

            fn refang_email(&self, unvalid: bool) -> String {
                let re_email = self.replace("[.]", ".").replace("[@]", "@");
                if CtfParty::is_email(&re_email, EmailMode::Light) || unvalid {
                    re_email
                } else {
                    self.to_string()
                }
            }

            // Hash functions
            fn md5(&self) -> String {
                format!("{:x}", compute(self.as_bytes()))
            }

            fn sha1(&self) -> String {
                let mut hasher = Sha1::new();
                digest::Digest::update(&mut hasher, self.as_bytes());
                format!("{:x}", digest::Digest::finalize(hasher))
            }

            fn sha2_256(&self) -> String {
                let mut hasher = Sha256::new();
                digest::Digest::update(&mut hasher, self.as_bytes());
                format!("{:x}", digest::Digest::finalize(hasher))
            }

            fn sha2_384(&self) -> String {
                let mut hasher = Sha384::new();
                digest::Digest::update(&mut hasher, self.as_bytes());
                format!("{:x}", digest::Digest::finalize(hasher))
            }

            fn sha2_512(&self) -> String {
                let mut hasher = Sha512::new();
                digest::Digest::update(&mut hasher, self.as_bytes());
                format!("{:x}", digest::Digest::finalize(hasher))
            }

            fn rmd160(&self) -> String {
                let mut hasher = Ripemd160Digest::new();
                digest::Digest::update(&mut hasher, self.as_bytes());
                format!("{:x}", digest::Digest::finalize(hasher))
            }

            // Flag formatting
            fn flag(&self, config: &FlagConfig) -> String {
                let content = match config.digest {
                    Some(DigestType::Md5) => CtfParty::md5(self),
                    Some(DigestType::Sha1) => CtfParty::sha1(self),
                    Some(DigestType::Sha2_256) => CtfParty::sha2_256(self),
                    Some(DigestType::Sha2_384) => CtfParty::sha2_384(self),
                    Some(DigestType::Sha2_512) => CtfParty::sha2_512(self),
                    Some(DigestType::Rmd160) => CtfParty::rmd160(self),
                    None => self.to_string(),
                };

                format!(
                    "{}{}{}{}{}",
                    config.prefix, config.enclosing.0, content, config.enclosing.1, config.suffix
                )
            }

            fn is_flag(&self, config: &FlagConfig) -> bool {
                let pattern = format!(
                    r"^{}\{}[[:print:]]+\{}{}$",
                    regex::escape(&config.prefix),
                    config.enclosing.0,
                    config.enclosing.1,
                    regex::escape(&config.suffix)
                );

                Regex::new(&pattern).unwrap().is_match(self)
            }

            // Hexadecimal encoding/decoding
            fn hex2dec(&self, prefix: &str, padding: usize) -> Result<String, String> {
                let cleaned = self.strip_prefix(prefix).unwrap_or(self);

                u128::from_str_radix(cleaned, 16)
                    .map(|n| {
                        let result = n.to_string();
                        if padding > 0 && result.len() < padding {
                            format!("{:0>padding$}", result, padding = padding)
                        } else {
                            result
                        }
                    })
                    .map_err(|e| e.to_string())
            }

            fn dec2hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                padding: usize,
            ) -> String {
                let n: u128 = self.parse().unwrap_or(0);
                let mut hex = format!("{:x}", n);

                if padding > 0 && hex.len() < padding {
                    hex = format!("{:0>padding$}", hex, padding = padding);
                }

                let hex = match case {
                    HexCase::Upper => hex.to_uppercase(),
                    HexCase::Lower => hex,
                };

                let prefixed: String = hex
                    .as_bytes()
                    .chunks(2)
                    .map(|c| format!("{}{}", prefixall, std::str::from_utf8(c).unwrap()))
                    .collect();

                format!("{}{}", prefix, prefixed)
            }

            fn to_hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String {
                let hex = match nibble {
                    Nibble::High => self
                        .bytes()
                        .flat_map(|b| vec![(b >> 4) & 0xF, b & 0xF])
                        .map(|b| format!("{:x}", b))
                        .collect::<String>(),
                    Nibble::Low => self
                        .bytes()
                        .flat_map(|b| vec![b & 0xF, (b >> 4) & 0xF])
                        .map(|b| format!("{:x}", b))
                        .collect::<String>(),
                };

                let hex = match case {
                    HexCase::Upper => hex.to_uppercase(),
                    HexCase::Lower => hex,
                };

                let prefixed: String = hex
                    .as_bytes()
                    .chunks(2)
                    .map(|c| format!("{}{}", prefixall, std::str::from_utf8(c).unwrap()))
                    .collect();

                format!("{}{}", prefix, prefixed)
            }

            fn from_hex(&self, prefix: &str, nibble: Nibble) -> Result<String, String> {
                let cleaned = self.strip_prefix(prefix).unwrap_or(self);

                if cleaned.len() % 2 != 0 {
                    return Err("Hex string must have even length".to_string());
                }

                let bytes: Vec<u8> = cleaned
                    .as_bytes()
                    .chunks(2)
                    .map(|chunk| {
                        let byte_str = std::str::from_utf8(chunk).unwrap();
                        u8::from_str_radix(byte_str, 16).unwrap()
                    })
                    .collect();

                let result = String::from_utf8(bytes).map_err(|e| e.to_string())?;

                Ok(match nibble {
                    Nibble::High => result,
                    Nibble::Low => {
                        // Swap nibbles
                        result
                            .bytes()
                            .map(|b| ((b & 0x0F) << 4) | ((b & 0xF0) >> 4))
                            .map(|b| b as char)
                            .collect()
                    }
                })
            }

            fn hex2bin(&self, prefix: &str, even: bool) -> Result<String, String> {
                let cleaned = self.strip_prefix(prefix).unwrap_or(self);

                let n = u128::from_str_radix(cleaned, 16).map_err(|e| e.to_string())?;
                let mut bin = format!("{:b}", n);

                if even && bin.len() % 2 != 0 {
                    bin = format!("0{}", bin);
                }

                Ok(bin)
            }

            fn bin2hex(&self, prefix: &str, prefixall: &str, case: HexCase) -> String {
                let n = u128::from_str_radix(self, 2).unwrap_or(0);
                let hex = format!("{:x}", n);

                let hex = match case {
                    HexCase::Upper => hex.to_uppercase(),
                    HexCase::Lower => hex,
                };

                let prefixed: String = hex
                    .as_bytes()
                    .chunks(2)
                    .map(|c| {
                        if c.len() == 2 {
                            format!("{}{}", prefixall, std::str::from_utf8(c).unwrap())
                        } else {
                            format!("{}{}", prefixall, std::str::from_utf8(c).unwrap())
                        }
                    })
                    .collect();

                format!("{}{}", prefix, prefixed)
            }

            fn from_hexipv4(&self, prefix: &str, nibble: Nibble) -> Result<String, String> {
                let cleaned = self.strip_prefix(prefix).unwrap_or(self);

                if cleaned.len() != 8 {
                    return Err("Invalid hex IPv4 address".to_string());
                }

                let octets: Vec<u8> = cleaned
                    .as_bytes()
                    .chunks(2)
                    .map(|c| u8::from_str_radix(std::str::from_utf8(c).unwrap(), 16).unwrap())
                    .collect();

                let octets = match nibble {
                    Nibble::High => octets,
                    Nibble::Low => octets.into_iter().rev().collect(),
                };

                Ok(format!(
                    "{}.{}.{}.{}",
                    octets[0], octets[1], octets[2], octets[3]
                ))
            }

            fn from_hexipv6(&self, prefix: &str) -> Result<String, String> {
                let cleaned = self.strip_prefix(prefix).unwrap_or(self);

                if cleaned.len() != 32 {
                    return Err("Invalid hex IPv6 address".to_string());
                }

                let bytes: Vec<u8> = cleaned
                    .as_bytes()
                    .chunks(2)
                    .map(|c| u8::from_str_radix(std::str::from_utf8(c).unwrap(), 16).unwrap())
                    .collect();

                // Convert bytes to IPv6 address
                let segments: Vec<u16> = bytes
                    .chunks(2)
                    .map(|c| ((c[0] as u16) << 8) | (c[1] as u16))
                    .collect();

                // Convert to IPv6Addr
                let addr = Ipv6Addr::new(
                    segments[0],
                    segments[1],
                    segments[2],
                    segments[3],
                    segments[4],
                    segments[5],
                    segments[6],
                    segments[7],
                );

                Ok(format!("[{}]", addr))
            }

            fn to_hexipv4(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String {
                let addr: Ipv4Addr = self.parse().unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
                let octets = addr.octets();

                let octets = match nibble {
                    Nibble::High => octets.to_vec(),
                    Nibble::Low => octets.into_iter().rev().collect(),
                };

                let hex: String = octets.iter().map(|b| format!("{:02x}", b)).collect();

                let hex = match case {
                    HexCase::Upper => hex.to_uppercase(),
                    HexCase::Lower => hex,
                };

                let prefixed: String = hex
                    .as_bytes()
                    .chunks(2)
                    .map(|c| format!("{}{}", prefixall, std::str::from_utf8(c).unwrap()))
                    .collect();

                format!("{}{}", prefix, prefixed)
            }

            // Leet speak
            fn leet(&self) -> String {
                let replacements = [
                    ('T', '7'),
                    ('t', '7'),
                    ('E', '3'),
                    ('e', '3'),
                    ('I', '1'),
                    ('i', '1'),
                    ('L', '1'),
                    ('l', '1'),
                    ('O', '0'),
                    ('o', '0'),
                    ('S', '5'),
                    ('s', '5'),
                    ('A', '4'),
                    ('a', '4'),
                    ('G', '6'),
                    ('g', '6'),
                    ('B', '8'),
                    ('b', '8'),
                ];

                let mut result = self.to_string();
                for (from, to) in replacements {
                    result = result.replace(from, &to.to_string());
                }
                result
            }

            // String stripping
            fn istrip(&self) -> String {
                self.chars().filter(|c| !c.is_whitespace()).collect()
            }

            // Validation
            fn is_ipv4(&self) -> bool {
                self.parse::<Ipv4Addr>().is_ok()
            }

            fn is_ipv6(&self) -> bool {
                self.parse::<Ipv6Addr>().is_ok()
            }

            fn is_ip(&self) -> bool {
                CtfParty::is_ipv4(self) || CtfParty::is_ipv6(self)
            }

            fn is_uri(&self, lax: bool) -> bool {
                let strict_schemes = [
                    "ftp", "http", "https", "ldap", "ldaps", "mailto", "ws", "wss",
                ];

                if let Ok(_) = Url::parse(self) {
                    if lax {
                        return true;
                    }

                    // Check if scheme is in strict list
                    if let Some(scheme_pos) = self.find(':') {
                        let scheme = &self[..scheme_pos];
                        return strict_schemes.contains(&scheme);
                    }
                }

                lax
            }

            fn is_domain(&self) -> bool {
                // Basic domain validation (lax, similar to Ruby version)
                let domain_regex = Regex::new(
                    r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$",
                )
                .unwrap();

                domain_regex.is_match(self) && self.len() <= 253 && self.len() >= 2
            }

            fn is_email(&self, mode: EmailMode) -> bool {
                let regex = match mode {
                    EmailMode::Rfc5322 => {
                        // Simplified RFC 5322 compliant
                        Regex::new(
                    r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$"
                ).unwrap()
                    }
                    EmailMode::Light => {
                        // Light version
                        Regex::new(
                    r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$"
                ).unwrap()
                    }
                    EmailMode::LightWithLength => {
                        // Light version with length limits
                        Regex::new(
                    r"^(?=[a-zA-Z0-9@.!#$%&'*+/=?^_`{|}~-]{6,254}$)(?=[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:(?=[a-zA-Z0-9-]{1,63}\\.)[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+(?=[a-zA-Z0-9-]{1,63}$)[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$"
                ).unwrap()
                    }
                };

                regex.is_match(self)
            }

            // ROT cipher
            fn rot(&self, shift: i32) -> String {
                self.chars()
                    .map(|c| {
                        if c.is_ascii_lowercase() {
                            let base = b'a';
                            let rotated = ((c as i32 - base as i32 + shift).rem_euclid(26)
                                + base as i32) as u8;
                            rotated as char
                        } else if c.is_ascii_uppercase() {
                            let base = b'A';
                            let rotated = ((c as i32 - base as i32 + shift).rem_euclid(26)
                                + base as i32) as u8;
                            rotated as char
                        } else {
                            c
                        }
                    })
                    .collect()
            }

            fn rot_all(&self) -> Vec<(i32, String)> {
                (1..=26).map(|i| (i, CtfParty::rot(self, i))).collect()
            }

            // XOR operations
            fn ulxor(&self, key: &str) -> String {
                let b1: Vec<u32> = self.chars().map(|c| c as u32).collect();
                let b2: Vec<u32> = key.chars().map(|c| c as u32).collect();

                let longest = b1.len().max(b2.len());
                let b1_padded: Vec<u32> =
                    vec![0; longest - b1.len()].into_iter().chain(b1).collect();
                let b2_padded: Vec<u32> =
                    vec![0; longest - b2.len()].into_iter().chain(b2).collect();

                b1_padded
                    .iter()
                    .zip(b2_padded.iter())
                    .map(|(a, b)| std::char::from_u32(a ^ b).unwrap_or('\u{FFFD}'))
                    .collect()
            }

            fn alxor(&self, key: &str) -> Result<String, String> {
                if !self.is_ascii() {
                    return Err("The string is not ASCII".to_string());
                }
                if !key.is_ascii() {
                    return Err("The key is not ASCII".to_string());
                }

                let b1: Vec<u8> = self.bytes().collect();
                let b2: Vec<u8> = key.bytes().collect();

                let longest = b1.len().max(b2.len());
                let b1_padded: Vec<u8> =
                    vec![0; longest - b1.len()].into_iter().chain(b1).collect();
                let b2_padded: Vec<u8> =
                    vec![0; longest - b2.len()].into_iter().chain(b2).collect();

                Ok(b1_padded
                    .iter()
                    .zip(b2_padded.iter())
                    .map(|(a, b)| a ^ b)
                    .map(|b| b as char)
                    .collect())
            }

            fn urxor(&self, key: &str) -> String {
                let b1: Vec<u32> = self.chars().map(|c| c as u32).collect();
                let b2: Vec<u32> = key.chars().map(|c| c as u32).collect();

                let longest = b1.len().max(b2.len());
                let mut b1_padded: Vec<u32> = b1;
                b1_padded.resize(longest, 0);
                let mut b2_padded: Vec<u32> = b2;
                b2_padded.resize(longest, 0);

                b1_padded
                    .iter()
                    .zip(b2_padded.iter())
                    .map(|(a, b)| std::char::from_u32(a ^ b).unwrap_or('\u{FFFD}'))
                    .collect()
            }

            fn arxor(&self, key: &str) -> Result<String, String> {
                if !self.is_ascii() {
                    return Err("The string is not ASCII".to_string());
                }
                if !key.is_ascii() {
                    return Err("The key is not ASCII".to_string());
                }

                let mut b1: Vec<u8> = self.bytes().collect();
                let mut b2: Vec<u8> = key.bytes().collect();

                let longest = b1.len().max(b2.len());
                b1.resize(longest, 0);
                b2.resize(longest, 0);

                Ok(b1
                    .iter()
                    .zip(b2.iter())
                    .map(|(a, b)| a ^ b)
                    .map(|b| b as char)
                    .collect())
            }
        }

        // Implement for String as well - just delegate to &str implementation
        impl CtfParty for String {
            fn to_b64(&self, mode: Base64Mode) -> String {
                CtfParty::to_b64(self.as_str(), mode)
            }

            fn from_b64(&self, mode: Base64Mode) -> Result<String, String> {
                CtfParty::from_b64(self.as_str(), mode)
            }

            fn is_b64(&self, mode: Base64Mode) -> bool {
                CtfParty::is_b64(self.as_str(), mode)
            }

            fn to_bin(&self, bitnumbering: BitNumbering) -> String {
                CtfParty::to_bin(self.as_str(), bitnumbering)
            }

            fn from_bin(&self, bitnumbering: BitNumbering) -> Result<String, String> {
                CtfParty::from_bin(self.as_str(), bitnumbering)
            }

            fn bin2dec(&self) -> Result<String, String> {
                CtfParty::bin2dec(self.as_str())
            }

            fn dec2bin(&self) -> Result<String, String> {
                CtfParty::dec2bin(self.as_str())
            }

            fn randomcase(&self) -> String {
                CtfParty::randomcase(self.as_str())
            }

            fn alternatecase(&self, shift: usize) -> String {
                CtfParty::alternatecase(self.as_str(), shift)
            }

            fn urlencode(&self) -> String {
                CtfParty::urlencode(self.as_str())
            }

            fn urldecode(&self) -> Result<String, String> {
                CtfParty::urldecode(self.as_str())
            }

            fn urlencode_data(&self) -> String {
                CtfParty::urlencode_data(self.as_str())
            }

            fn urldecode_data(&self) -> Result<String, String> {
                CtfParty::urldecode_data(self.as_str())
            }

            fn htmlescape(&self) -> String {
                CtfParty::htmlescape(self.as_str())
            }

            fn htmlunescape(&self) -> String {
                CtfParty::htmlunescape(self.as_str())
            }

            fn urlencode_component(&self) -> String {
                CtfParty::urlencode_component(self.as_str())
            }

            fn urldecode_component(&self) -> Result<String, String> {
                CtfParty::urldecode_component(self.as_str())
            }

            fn to_dec(&self) -> String {
                CtfParty::to_dec(self.as_str())
            }

            fn from_dec(&self) -> Result<String, String> {
                CtfParty::from_dec(self.as_str())
            }

            fn defang_ip(&self, unvalid: bool) -> String {
                CtfParty::defang_ip(self.as_str(), unvalid)
            }

            fn refang_ip(&self, unvalid: bool) -> String {
                CtfParty::refang_ip(self.as_str(), unvalid)
            }

            fn defang_uri(&self) -> String {
                CtfParty::defang_uri(self.as_str())
            }

            fn refang_uri(&self) -> Result<String, String> {
                CtfParty::refang_uri(self.as_str())
            }

            fn defang_domain(&self, unvalid: bool) -> String {
                CtfParty::defang_domain(self.as_str(), unvalid)
            }

            fn refang_domain(&self, unvalid: bool) -> String {
                CtfParty::refang_domain(self.as_str(), unvalid)
            }

            fn defang_email(&self, unvalid: bool) -> String {
                CtfParty::defang_email(self.as_str(), unvalid)
            }

            fn refang_email(&self, unvalid: bool) -> String {
                CtfParty::refang_email(self.as_str(), unvalid)
            }

            fn md5(&self) -> String {
                CtfParty::md5(self.as_str())
            }

            fn sha1(&self) -> String {
                CtfParty::sha1(self.as_str())
            }

            fn sha2_256(&self) -> String {
                CtfParty::sha2_256(self.as_str())
            }

            fn sha2_384(&self) -> String {
                CtfParty::sha2_384(self.as_str())
            }

            fn sha2_512(&self) -> String {
                CtfParty::sha2_512(self.as_str())
            }

            fn rmd160(&self) -> String {
                CtfParty::rmd160(self.as_str())
            }

            fn flag(&self, config: &FlagConfig) -> String {
                CtfParty::flag(self.as_str(), config)
            }

            fn is_flag(&self, config: &FlagConfig) -> bool {
                CtfParty::is_flag(self.as_str(), config)
            }

            fn hex2dec(&self, prefix: &str, padding: usize) -> Result<String, String> {
                CtfParty::hex2dec(self.as_str(), prefix, padding)
            }

            fn dec2hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                padding: usize,
            ) -> String {
                CtfParty::dec2hex(self.as_str(), prefix, prefixall, case, padding)
            }

            fn to_hex(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String {
                CtfParty::to_hex(self.as_str(), prefix, prefixall, case, nibble)
            }

            fn from_hex(&self, prefix: &str, nibble: Nibble) -> Result<String, String> {
                CtfParty::from_hex(self.as_str(), prefix, nibble)
            }

            fn hex2bin(&self, prefix: &str, even: bool) -> Result<String, String> {
                CtfParty::hex2bin(self.as_str(), prefix, even)
            }

            fn bin2hex(&self, prefix: &str, prefixall: &str, case: HexCase) -> String {
                CtfParty::bin2hex(self.as_str(), prefix, prefixall, case)
            }

            fn from_hexipv4(&self, prefix: &str, nibble: Nibble) -> Result<String, String> {
                CtfParty::from_hexipv4(self.as_str(), prefix, nibble)
            }

            fn from_hexipv6(&self, prefix: &str) -> Result<String, String> {
                CtfParty::from_hexipv6(self.as_str(), prefix)
            }

            fn to_hexipv4(
                &self,
                prefix: &str,
                prefixall: &str,
                case: HexCase,
                nibble: Nibble,
            ) -> String {
                CtfParty::to_hexipv4(self.as_str(), prefix, prefixall, case, nibble)
            }

            fn leet(&self) -> String {
                CtfParty::leet(self.as_str())
            }

            fn istrip(&self) -> String {
                CtfParty::istrip(self.as_str())
            }

            fn is_ipv4(&self) -> bool {
                CtfParty::is_ipv4(self.as_str())
            }

            fn is_ipv6(&self) -> bool {
                CtfParty::is_ipv6(self.as_str())
            }

            fn is_ip(&self) -> bool {
                CtfParty::is_ip(self.as_str())
            }

            fn is_uri(&self, lax: bool) -> bool {
                CtfParty::is_uri(self.as_str(), lax)
            }

            fn is_domain(&self) -> bool {
                CtfParty::is_domain(self.as_str())
            }

            fn is_email(&self, mode: EmailMode) -> bool {
                CtfParty::is_email(self.as_str(), mode)
            }

            fn rot(&self, shift: i32) -> String {
                CtfParty::rot(self.as_str(), shift)
            }

            fn rot_all(&self) -> Vec<(i32, String)> {
                CtfParty::rot_all(self.as_str())
            }

            fn ulxor(&self, key: &str) -> String {
                CtfParty::ulxor(self.as_str(), key)
            }

            fn alxor(&self, key: &str) -> Result<String, String> {
                CtfParty::alxor(self.as_str(), key)
            }

            fn urxor(&self, key: &str) -> String {
                CtfParty::urxor(self.as_str(), key)
            }

            fn arxor(&self, key: &str) -> Result<String, String> {
                CtfParty::arxor(self.as_str(), key)
            }
        }
    }

    pub use zerowidth_stego::*;

    pub mod zerowidth_stego {
        //! Zero-Width Unicode Character Steganography
        //!
        //! A Rust port of the JavaScript library by Kei Misawa (MIT License).
        //! Encodes/decodes hidden data using zero-width Unicode characters embedded in visible text.
        //!
        //! # Default zero-width characters
        //!
        //! - U+200C  Zero Width Non-Joiner
        //! - U+200D  Zero Width Joiner
        //! - U+202C  Pop Directional Formatting
        //! - U+FEFF  Zero Width No-Break Space (BOM)
        //!
        //! # Example
        //!
        //! ```
        //! use steganographer::UnicodeSteganographer;
        //!
        //! let steg = UnicodeSteganographer::new();
        //!
        //! // Encode: hide "secret" inside "Hello World"
        //! let encoded = steg.encode_text("Hello World", "secret");
        //!
        //! // Decode: extract both the original and hidden text
        //! let decoded = steg.decode_text(&encoded);
        //! assert_eq!(decoded.original_text, "Hello World");
        //! assert_eq!(decoded.hidden_text, "secret");
        //! ```

        use rand::Rng;
        use std::collections::HashSet;

        // ---------------------------------------------------------------------------
        // Public result types
        // ---------------------------------------------------------------------------

        /// Result of decoding text-mode steganography.
        #[derive(Debug, Clone, PartialEq, Eq)]
        pub struct DecodedText {
            /// The original visible text (with zero-width characters stripped).
            pub original_text: String,
            /// The hidden message that was embedded.
            pub hidden_text: String,
        }

        /// Result of decoding binary-mode steganography.
        #[derive(Debug, Clone, PartialEq, Eq)]
        pub struct DecodedBinary {
            /// The original visible text (with zero-width characters stripped).
            pub original_text: String,
            /// The hidden binary payload.
            pub hidden_data: Vec<u8>,
        }

        // ---------------------------------------------------------------------------
        // Core struct
        // ---------------------------------------------------------------------------

        /// A zero-width Unicode character steganographic encoder/decoder.
        ///
        /// The encoder converts hidden data into sequences of zero-width Unicode
        /// characters, shuffles them into a cover text, and produces a visually
        /// identical string. The decoder extracts the hidden data and recovers the
        /// original cover text.
        ///
        /// # Thread safety
        ///
        /// The encoding/decoding methods take `&self` and can be called concurrently
        /// from multiple threads. Mutation (`set_use_chars`) requires `&mut self`.
        #[derive(Debug, Clone)]
        pub struct UnicodeSteganographer {
            /// The zero-width characters used for encoding, ordered by their numeric
            /// digit value (chars[0] represents digit 0, chars[1] represents digit 1,
            /// etc.).
            chars: Vec<char>,
            /// The radix (base) for encoding — equal to `chars.len()`.
            radix: u32,
            /// Number of zero-width characters needed to encode one BMP text character.
            code_length_text: usize,
            /// Number of zero-width characters needed to encode one byte.
            code_length_binary: usize,
        }

        impl Default for UnicodeSteganographer {
            fn default() -> Self {
                Self::new()
            }
        }

        impl UnicodeSteganographer {
            /// Creates a new encoder with the default zero-width character set:
            /// `\u{200C}\u{200D}\u{202C}\u{FEFF}` (radix 4).
            ///
            /// This gives a code-length of 8 for text (each BMP character becomes 8
            /// zero-width characters) and 4 for binary (each byte becomes 4 zero-width
            /// characters).
            pub fn new() -> Self {
                let mut steg = Self {
                    chars: Vec::new(),
                    radix: 0,
                    code_length_text: 0,
                    code_length_binary: 0,
                };
                steg.set_use_chars("\u{200C}\u{200D}\u{202C}\u{FEFF}");
                steg
            }

            /// Sets the zero-width characters used for encoding.
            ///
            /// `new_chars` must contain at least 2 distinct characters. Each character
            /// maps to one digit in the chosen radix (the radix equals the number of
            /// characters).
            ///
            /// # Panics
            ///
            /// Panics if `new_chars` contains fewer than 2 characters.
            pub fn set_use_chars(&mut self, new_chars: &str) {
                let chars: Vec<char> = new_chars.chars().collect();
                assert!(chars.len() >= 2, "at least 2 characters required");

                self.radix = chars.len() as u32;

                // In the original JS library the max codepoint considered is 65536
                // because JavaScript strings are UTF-16.  We keep the same value so
                // that the Rust encoder is interoperable with the JS version for all
                // BMP characters (U+0000 – U+FFFF).
                let max_text = 65536.0_f64;
                let max_binary = 256.0_f64;
                let radix_f = self.radix as f64;

                self.code_length_text = max_text.log(radix_f).ceil() as usize;
                self.code_length_binary = max_binary.log(radix_f).ceil() as usize;

                self.chars = chars;
            }

            /// Returns the current radix (base) used for encoding.
            pub fn radix(&self) -> u32 {
                self.radix
            }

            /// Returns the current zero-width character set.
            pub fn chars(&self) -> &[char] {
                &self.chars
            }

            // -----------------------------------------------------------------------
            // Public API — encode
            // -----------------------------------------------------------------------

            /// Encodes a hidden text string into a cover text string.
            ///
            /// Each character of `hidden` is converted to a sequence of zero-width
            /// characters (base-`radix` representation) and then shuffled among the
            /// characters of `text`. The result looks visually identical to `text`.
            ///
            /// **Note:** Supplementary Unicode characters (code points > U+FFFF) are
            /// not supported because the code length is calculated for BMP-only range.
            /// Encoding such characters will produce incorrect results.
            pub fn encode_text(&self, text: &str, hidden: &str) -> String {
                let encoded = self.encode_to_zwc_text(hidden);
                self.combine_shuffle(text, &encoded, self.code_length_text)
            }

            pub fn extract_zerowidth_from_file(&self, filepath: &str) -> Option<String> {
                let content = std::fs::read(filepath).ok()?;
                let text = String::from_utf8_lossy(&content).to_string();
                let zw_chars = text
                    .chars()
                    .filter(|c| self.chars.contains(c))
                    .collect::<String>();
                Some(zw_chars)
            }
            // try:
            //     with open(filepath, 'rb') as f:
            //         content = f.read()

            //     # Decode as UTF-8 and extract zero-width chars
            //     try:
            //         text = content.decode('utf-8', errors='ignore')
            //         zw_chars = [c for c in text if c in ZERO_WIDTH_MAP]
            //         return ''.join(zw_chars)
            //     except:
            //         return None
            // except Exception as e:
            //     print(f"Error reading {filepath}: {e}")
            //     return None

            /// Encodes a hidden binary payload into a cover text string.
            ///
            /// Each byte of `data` is converted to a sequence of zero-width characters
            /// and shuffled into `text`.
            pub fn encode_binary(&self, text: &str, data: &[u8]) -> String {
                let encoded = self.encode_to_zwc_binary(data);
                self.combine_shuffle(text, &encoded, self.code_length_binary)
            }

            // -----------------------------------------------------------------------
            // Public API — decode
            // -----------------------------------------------------------------------

            /// Decodes a steganographic string that was encoded with [`encode_text`].
            ///
            /// Returns both the original cover text and the hidden message.
            pub fn decode_text(&self, text: &str) -> DecodedText {
                let (original, hidden) = self.split_zwc(text);
                DecodedText {
                    original_text: original,
                    hidden_text: self.decode_from_zwc_text(&hidden),
                }
            }

            /// Decodes a steganographic string that was encoded with [`encode_binary`].
            ///
            /// Returns both the original cover text and the hidden binary payload.
            pub fn decode_binary(&self, text: &str) -> DecodedBinary {
                let (original, hidden) = self.split_zwc(text);
                DecodedBinary {
                    original_text: original,
                    hidden_data: self.decode_from_zwc_binary(&hidden),
                }
            }

            // -----------------------------------------------------------------------
            // Internal — encode helpers
            // -----------------------------------------------------------------------

            /// Converts a text string into a sequence of zero-width characters.
            ///
            /// Each `char` is converted to its Unicode code point, represented in base
            /// `self.radix`, padded to `self.code_length_text` digits, and each digit
            /// is mapped to the corresponding zero-width character.
            fn encode_to_zwc_text(&self, s: &str) -> String {
                let mut result = String::with_capacity(s.len() * self.code_length_text);

                for c in s.chars() {
                    let code = c as u32;
                    let digit_str = format_radix(code, self.radix);

                    // Left-pad with '0' to code_length_text digits.
                    let pad = self.code_length_text.saturating_sub(digit_str.len());
                    for _ in 0..pad {
                        result.push('0');
                    }
                    result.push_str(&digit_str);
                }

                // Replace each digit character with the corresponding zero-width char.
                self.replace_digits_with_zwc(&mut result);
                result
            }

            /// Converts a byte slice into a sequence of zero-width characters.
            fn encode_to_zwc_binary(&self, data: &[u8]) -> String {
                let mut result = String::with_capacity(data.len() * self.code_length_binary);

                for &byte in data {
                    let digit_str = format_radix(byte as u32, self.radix);

                    let pad = self.code_length_binary.saturating_sub(digit_str.len());
                    for _ in 0..pad {
                        result.push('0');
                    }
                    result.push_str(&digit_str);
                }

                self.replace_digits_with_zwc(&mut result);
                result
            }

            /// Replaces digit characters ('0'..'9','a'..'z') in `s` with their
            /// corresponding zero-width character from `self.chars`.
            ///
            /// Digits are processed in reverse order (highest index first) so that
            /// replacing multi-character digit representations (e.g. "10") does not
            /// corrupt lower-index single-character digits (e.g. "0" or "1").
            ///
            /// **Note:** The original JS library processes digits 0 → radix-1 in
            /// forward order. For radix ≤ 10 this is equivalent. For radix > 10 the
            /// JS code has a subtle bug (it uses `new RegExp(10, 'g')` which matches
            /// the literal string "10" rather than the hex digit "a"). This Rust port
            /// intentionally matches the JS behaviour for radix ≤ 10.
            fn replace_digits_with_zwc(&self, s: &mut String) {
                // Process in reverse to avoid prefix conflicts.
                for i in (0..self.radix).rev() {
                    let from = digit_char(i);
                    let to = self.chars[i as usize];
                    *s = s.replace(from, &to.to_string());
                }
            }

            // -----------------------------------------------------------------------
            // Internal — decode helpers
            // -----------------------------------------------------------------------

            /// Splits a steganographic string into its visible and zero-width parts.
            fn split_zwc(&self, text: &str) -> (String, String) {
                let zwc_set: HashSet<char> = self.chars.iter().copied().collect();

                let mut original = String::with_capacity(text.len());
                let mut hidden = String::new();

                for c in text.chars() {
                    if zwc_set.contains(&c) {
                        hidden.push(c);
                    } else {
                        original.push(c);
                    }
                }

                (original, hidden)
            }

            /// Decodes a zero-width character sequence back into a text string.
            fn decode_from_zwc_text(&self, s: &str) -> String {
                let digit_str = self.zwc_to_digits(s);
                let cl = self.code_length_text;

                let chars: Vec<char> = digit_str.chars().collect();
                let mut result = String::with_capacity(chars.len() / cl);

                let mut i = 0;
                while i + cl <= chars.len() {
                    let chunk: String = chars[i..i + cl].iter().collect();
                    if let Ok(code_point) = u32::from_str_radix(&chunk, self.radix) {
                        if let Some(c) = char::from_u32(code_point) {
                            result.push(c);
                        }
                    }
                    i += cl;
                }

                result
            }

            /// Decodes a zero-width character sequence back into a byte vector.
            fn decode_from_zwc_binary(&self, s: &str) -> Vec<u8> {
                let digit_str = self.zwc_to_digits(s);
                let cl = self.code_length_binary;

                let chars: Vec<char> = digit_str.chars().collect();
                let mut result = Vec::with_capacity(chars.len() / cl);

                let mut i = 0;
                while i + cl <= chars.len() {
                    let chunk: String = chars[i..i + cl].iter().collect();
                    if let Ok(byte) = u8::from_str_radix(&chunk, self.radix) {
                        result.push(byte);
                    }
                    i += cl;
                }

                result
            }

            /// Replaces each zero-width character in `s` with its corresponding digit
            /// character.
            fn zwc_to_digits(&self, s: &str) -> String {
                let mut result = s.to_string();
                for (i, zwc) in self.chars.iter().enumerate() {
                    result = result.replace(&zwc.to_string(), &digit_char(i as _));
                }
                result
            }

            // -----------------------------------------------------------------------
            // Internal — shuffle
            // -----------------------------------------------------------------------

            /// Combines visible text chunks with encoded zero-width chunks using
            /// randomised interleaving, preserving the approximate ratio of visible to
            /// hidden chunks so the zero-width characters are evenly distributed.
            fn combine_shuffle(&self, text: &str, encoded: &str, code_length: usize) -> String {
                let visible_chunks = split_into_chunks(text);
                let hidden_chunks = split_by_size(encoded, code_length);

                if hidden_chunks.is_empty() {
                    return text.to_string();
                }

                let ratio = visible_chunks.len() as f64
                    / (visible_chunks.len() + hidden_chunks.len()) as f64;

                let mut result = Vec::with_capacity(visible_chunks.len() + hidden_chunks.len());
                let mut rng = rand::thread_rng();

                let mut vi = 0; // visible index
                let mut hi = 0; // hidden index

                while vi < visible_chunks.len() && hi < hidden_chunks.len() {
                    if rng.gen::<f64>() <= ratio {
                        result.push(&visible_chunks[vi]);
                        vi += 1;
                    } else {
                        result.push(&hidden_chunks[hi]);
                        hi += 1;
                    }
                }

                // Drain remaining chunks.
                while vi < visible_chunks.len() {
                    result.push(&visible_chunks[vi]);
                    vi += 1;
                }
                while hi < hidden_chunks.len() {
                    result.push(&hidden_chunks[hi]);
                    hi += 1;
                }

                result.iter().map(|s| s.as_str()).collect::<String>()
            }
        }

        // ---------------------------------------------------------------------------
        // Free helper functions
        // ---------------------------------------------------------------------------

        /// Formats `n` as a string in the given `radix` (base 2–36).
        ///
        /// Uses the same digit conventions as JavaScript's `Number.prototype.toString`:
        /// digits 0–9 then letters a–z.
        fn format_radix(mut n: u32, radix: u32) -> String {
            assert!((2..=36).contains(&radix), "radix must be between 2 and 36");

            if n == 0 {
                return "0".to_string();
            }

            let mut buf = Vec::with_capacity(32);
            while n > 0 {
                buf.push(char::from_digit(n % radix, radix).unwrap());
                n /= radix;
            }
            buf.reverse();
            buf.into_iter().collect()
        }

        /// Returns the single-character digit representation for the given index
        /// (0 → '0', 9 → '9', 10 → 'a', 35 → 'z').
        fn digit_char(idx: u32) -> &'static str {
            // Use a small lookup table to avoid formatting overhead.
            const DIGITS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
            debug_assert!((idx as usize) < DIGITS.len());
            // SAFETY: all bytes in DIGITS are ASCII, so they are valid UTF-8.
            unsafe { std::str::from_utf8_unchecked(&DIGITS[idx as usize..idx as usize + 1]) }
        }

        /// Splits a string into per-character chunks for shuffling.
        ///
        /// This mirrors the JavaScript implementation's splitting logic which divides
        /// the visible text into small chunks (by Unicode block ranges) so that
        /// zero-width characters can be interleaved.  Using individual `char`s is
        /// equivalent for most practical purposes and avoids the massive regex.
        fn split_into_chunks(text: &str) -> Vec<String> {
            text.chars().map(|c| c.to_string()).collect()
        }

        /// Splits a string into fixed-size chunks of `size` characters.
        fn split_by_size(s: &str, size: usize) -> Vec<String> {
            if size == 0 {
                return Vec::new();
            }

            let chars: Vec<char> = s.chars().collect();
            let mut result = Vec::with_capacity((chars.len() + size - 1) / size);
            let mut i = 0;

            while i < chars.len() {
                let end = (i + size).min(chars.len());
                result.push(chars[i..end].iter().collect());
                i += size;
            }

            result
        }

        // ---------------------------------------------------------------------------
        // Tests
        // ---------------------------------------------------------------------------

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

            #[test]
            fn test_roundtrip_text_ascii() {
                let steg = UnicodeSteganographer::new();
                let cover = "Hello, World!";
                let hidden = "secret message";

                let encoded = steg.encode_text(cover, hidden);
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, hidden);
            }

            #[test]
            fn test_roundtrip_text_cjk() {
                let steg = UnicodeSteganographer::new();
                let cover = "你好世界";
                let hidden = "隐藏信息";

                let encoded = steg.encode_text(cover, hidden);
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, hidden);
            }

            #[test]
            fn test_roundtrip_binary() {
                let steg = UnicodeSteganographer::new();
                let cover = "Visible text";
                let data: &[u8] = b"\x00\x01\x02\xff\xfe\x80\x7f";

                let encoded = steg.encode_binary(cover, data);
                let decoded = steg.decode_binary(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_data, data);
            }

            #[test]
            fn test_empty_hidden_text() {
                let steg = UnicodeSteganographer::new();
                let cover = "No hidden message";

                let encoded = steg.encode_text(cover, "");
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, "");
            }

            #[test]
            fn test_empty_hidden_binary() {
                let steg = UnicodeSteganographer::new();
                let cover = "No hidden data";

                let encoded = steg.encode_binary(cover, &[]);
                let decoded = steg.decode_binary(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert!(decoded.hidden_data.is_empty());
            }

            #[test]
            fn test_encoded_text_looks_identical() {
                let steg = UnicodeSteganographer::new();
                let cover = "The quick brown fox jumps over the lazy dog.";
                let hidden = "invisible";

                let encoded = steg.encode_text(cover, hidden);

                // After stripping zero-width characters, the result must equal the
                // original cover text.
                let cleaned: String = encoded
                    .chars()
                    .filter(|c| !['\u{200C}', '\u{200D}', '\u{202C}', '\u{FEFF}'].contains(c))
                    .collect();

                assert_eq!(cleaned, cover);
            }

            #[test]
            fn test_custom_chars() {
                let mut steg = UnicodeSteganographer::new();
                steg.set_use_chars("\u{200B}\u{200C}\u{200D}");
                // radix = 3

                let cover = "test";
                let hidden = "ab";

                let encoded = steg.encode_text(cover, hidden);
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, hidden);
            }

            #[test]
            fn test_format_radix() {
                assert_eq!(format_radix(0, 4), "0");
                assert_eq!(format_radix(1, 4), "1");
                assert_eq!(format_radix(4, 4), "10");
                assert_eq!(format_radix(255, 16), "ff");
                assert_eq!(format_radix(255, 2), "11111111");
                assert_eq!(format_radix(65535, 4), "33333333");
            }

            #[test]
            fn test_digit_char() {
                assert_eq!(digit_char(0), "0");
                assert_eq!(digit_char(9), "9");
                assert_eq!(digit_char(10), "a");
                assert_eq!(digit_char(35), "z");
            }

            #[test]
            fn test_multiple_roundtrips() {
                let steg = UnicodeSteganographer::new();
                let cover = "Envelope text here";

                let hidden1 = "first secret";
                let enc1 = steg.encode_text(cover, hidden1);
                let dec1 = steg.decode_text(&enc1);
                assert_eq!(dec1.hidden_text, hidden1);

                let hidden2 = "second secret message";
                let enc2 = steg.encode_text(cover, hidden2);
                let dec2 = steg.decode_text(&enc2);
                assert_eq!(dec2.hidden_text, hidden2);
            }

            #[test]
            fn test_special_characters_in_cover() {
                let steg = UnicodeSteganographer::new();
                let cover = "Hi!\n\tNew line & <tag> \"quotes\"";
                let hidden = "x";

                let encoded = steg.encode_text(cover, hidden);
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, hidden);
            }

            #[test]
            fn test_long_hidden_text() {
                let steg = UnicodeSteganographer::new();
                let cover = "short";
                let hidden = "This is a much longer hidden message than the cover text.";

                let encoded = steg.encode_text(cover, hidden);
                let decoded = steg.decode_text(&encoded);

                assert_eq!(decoded.original_text, cover);
                assert_eq!(decoded.hidden_text, hidden);
            }
        }
    }

    ///convert_to_pinyin_with_non_chinese
    ///```ignore
    /// use doe::ctf::*;
    /// convert_to_pinyin_with_non_chinese("ctf 我来测试一下 this code").dprintln();//ctf_wo_lai_ce_shi_yi_xia_this_code
    ///```
    ///
    pub fn convert_to_pinyin_with_non_chinese(input: &str) -> String {
        use crate::*;
        use pinyin::ToPinyin;
        input
            .split_to_vec(" ")
            .iter()
            .map(|s| {
                if contains_chinese(s) {
                    s.as_str()
                        .to_pinyin()
                        .map(|s| s.unwrap().plain())
                        .collect::<Vec<_>>()
                        .join("_")
                } else {
                    s.to_string()
                }
            })
            .collect::<Vec<String>>()
            .join("_")
    }
    ///contains_chinese
    ///```ignore
    ///contains_chinese("span测试").dprintln();//true
    ///contains_chinese("span").dprintln();//false
    ///```
    ///
    pub fn contains_chinese(text: &str) -> bool {
        use regex::Regex;
        let chinese_regex = Regex::new(r"[\p{Han}]").unwrap();
        chinese_regex.is_match(text)
    }
    ///parse_html
    ///```rust
    ///parse_html(html,"span", None).dprintln();//find all span
    ///parse_html(html,"h2", Some("id")).dprintln(); //find all h2 and get id value
    ///```
    ///
    pub fn parse_html<T: ToString>(html: T, selectors: T, attr: Option<T>) -> Vec<String> {
        use scraper::{Html, Selector};
        let html = html.to_string();
        let selectors = selectors.to_string();
        let document = Html::parse_document(&html);
        let img_selector = Selector::parse(&selectors).expect("Failed to parse selector");
        let mut res = Vec::new();
        if let Some(attr) = attr {
            let attr = attr.to_string();
            for element in document.select(&img_selector) {
                if let Some(src) = element.value().attr(&attr) {
                    res.push(src.to_string());
                }
            }
        } else {
            for element in document.select(&img_selector) {
                res.push(element.html());
            }
        }
        res
    }

    pub fn parse_html_get_innner_html<T: ToString>(html: T, selectors: T) -> Vec<String> {
        use scraper::{Html, Selector};
        let html = html.to_string();
        let selectors = selectors.to_string();
        let document = Html::parse_document(&html);
        let img_selector = Selector::parse(&selectors).expect("Failed to parse selector");
        let mut res = Vec::new();
        for element in document.select(&img_selector) {
            res.push(
                element
                    .text()
                    .into_iter()
                    .map(|s| s.trim().to_string())
                    .collect::<Vec<_>>()
                    .join("\t"),
            );
        }
        res
    }

    pub fn find_png_urls<T: ToString>(text: T) -> Vec<String> {
        use regex::Regex;
        let text = text.to_string();
        let re = Regex::new(r#"https?://[^\s\"']+\.(?:png|PNG)"#).expect("Failed to compile regex");
        re.find_iter(&text)
            .map(|m| m.as_str().to_string())
            .collect()
    }

    pub fn find_urls<T: ToString>(text: T) -> Vec<String> {
        use regex::Regex;
        let text = text.to_string();
        let re = Regex::new(r#"https?://[^\s"']+"#).expect("Failed to compile regex");
        re.find_iter(&text)
            .map(|m| m.as_str().to_string())
            .collect()
    }

    pub fn hex_encode<T: AsRef<[u8]>>(data: T) -> String {
        hex::encode(data)
    }

    pub fn hex_decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
        Ok(hex::decode(data).unwrap())
    }

    pub fn base64_encode<T: AsRef<[u8]>>(s: T) -> String {
        use base64::{engine::general_purpose, Engine as _};
        general_purpose::STANDARD_NO_PAD.encode(s)
    }
    pub fn base64_decode<T: AsRef<[u8]>>(s: T) -> Vec<u8> {
        use base64::{engine::general_purpose, Engine as _};
        general_purpose::STANDARD_NO_PAD.decode(s).unwrap()
    }

    pub fn url_encode(url: &str) -> String {
        use percent_encoding::{percent_decode_str, utf8_percent_encode};
        let encoded = utf8_percent_encode(url, percent_encoding::NON_ALPHANUMERIC);
        encoded.to_string()
    }
    pub fn url_decode(url: &str) -> String {
        use percent_encoding::{percent_decode_str, utf8_percent_encode};
        let decoded = percent_decode_str(url).decode_utf8().unwrap();
        decoded.to_string()
    }
    ///unicode_to_chinese
    /// ```rust
    ///   assert_eq!(chinese_to_unicode("学习").unwrap(),"\\u5b66\\u4e60");
    ///   assert_eq!(unicode_to_chinese("\\u5b66\\u4e60").unwrap(),"学习");
    /// ```
    ///
    pub fn unicode_to_chinese(unicode_str: impl ToString) -> Option<String> {
        use unicode_segmentation::UnicodeSegmentation;
        let converted = unicode_str
            .to_string()
            .split("\\u")
            .filter(|&segment| !segment.is_empty())
            .map(|segment| u32::from_str_radix(segment, 16))
            .collect::<Result<Vec<u32>, _>>()
            .ok()
            .map(|code_points| {
                code_points
                    .iter()
                    .map(|&code_point| std::char::from_u32(code_point).unwrap_or('\u{FFFD}'))
                    .collect::<String>()
            });
        converted
    }
    ///chinese_to_unicode
    /// ```rust
    ///   assert_eq!(chinese_to_unicode("学习").unwrap(),"\\u5b66\\u4e60");
    ///   assert_eq!(unicode_to_chinese("\\u5b66\\u4e60").unwrap(),"学习");
    /// ```
    ///
    pub fn chinese_to_unicode(chinese_str: &str) -> Option<String> {
        let converted = chinese_str
            .chars()
            .map(|ch| ch.escape_unicode().to_string())
            .collect::<Vec<String>>()
            .join("");
        Some(converted.replace("{", "").replace("}", ""))
    }

    pub mod packet {
        use anyhow::{Context, Result};

        // ==========================================
        // DNS Decoder
        // ==========================================

        #[derive(Debug, Clone)]
        pub struct DnsPacket {
            pub packet_length: usize,
            pub transaction_id: u16,
            pub flags: u16,
            pub is_response: bool,
            pub query_count: u16,
            pub answer_count: u16,
            pub return_code: u16,
            pub queries: Vec<DnsQuery>,
            pub answers: Vec<DnsAnswer>,
        }

        #[derive(Debug, Clone)]
        pub struct DnsQuery {
            pub domain: String,
            pub query_type: String,
            pub query_type_raw: u16,
        }

        #[derive(Debug, Clone)]
        pub struct DnsAnswer {
            pub name: String,
            pub record_type: String,
            pub record_type_raw: u16,
            pub ttl: u32,
            pub rdata: DnsRdata,
        }

        #[derive(Debug, Clone)]
        pub enum DnsRdata {
            A { ipv4: String },
            Cname { target: String },
            Unknown { raw: Vec<u8> },
        }

        const DNS_TYPES: &[(u16, &str)] = &[(1, "A (IPv4)"), (5, "CNAME (别名)")];

        fn decode_domain(data: &[u8], offset: usize) -> Result<(String, usize)> {
            let mut domain = Vec::new();
            let mut pos = offset;

            loop {
                let len = *data
                    .get(pos)
                    .context("DNS domain parsing out of bounds (reading label length)")?;

                if len == 0 {
                    pos += 1;
                    break;
                }

                if (len & 0xC0) == 0xC0 {
                    let b2 = *data
                        .get(pos + 1)
                        .context("DNS domain parsing out of bounds (reading pointer)")?;
                    let pointer = (((len & 0x3F) as usize) << 8) | b2 as usize;
                    pos += 2;
                    let (sub, _) = decode_domain(data, pointer)?;
                    domain.push(sub);
                    break;
                }

                pos += 1;
                let end = pos + len as usize;
                let label_bytes = data
                    .get(pos..end)
                    .context("DNS domain parsing out of bounds (reading label bytes)")?;

                let label = String::from_utf8_lossy(label_bytes).to_string();
                domain.push(label);
                pos = end;
            }

            Ok((domain.join("."), pos))
        }

        fn get_type_str(qtype: u16) -> String {
            DNS_TYPES
                .iter()
                .find(|(t, _)| *t == qtype)
                .map(|(_, s)| s.to_string())
                .unwrap_or_else(|| format!("未知({})", qtype))
        }

        fn decode_dns_packet(data: &[u8]) -> Result<DnsPacket> {
            if data.len() < 12 {
                anyhow::bail!("DNS packet too short (min 12 bytes)");
            }

            let tx_id = u16::from_be_bytes([data[0], data[1]]);
            let flags = u16::from_be_bytes([data[2], data[3]]);
            let qdcount = u16::from_be_bytes([data[4], data[5]]);
            let ancount = u16::from_be_bytes([data[6], data[7]]);

            let qr = (flags >> 15) & 0x1;
            let rcode = flags & 0xF;

            let mut pos = 12;
            let mut queries = Vec::new();

            for _ in 0..qdcount {
                let (domain, new_pos) = decode_domain(data, pos)?;
                pos = new_pos;

                let qtype_bytes = data
                    .get(pos..pos + 4)
                    .context("DNS query section out of bounds")?;
                let qtype = u16::from_be_bytes([qtype_bytes[0], qtype_bytes[1]]);
                pos += 4;

                queries.push(DnsQuery {
                    domain,
                    query_type: get_type_str(qtype),
                    query_type_raw: qtype,
                });
            }

            let mut answers = Vec::new();
            for _ in 0..ancount {
                let (name, new_pos) = decode_domain(data, pos)?;
                pos = new_pos;

                let ans_header = data
                    .get(pos..pos + 10)
                    .context("DNS answer header out of bounds")?;

                let rtype = u16::from_be_bytes([ans_header[0], ans_header[1]]);
                let _rclass = u16::from_be_bytes([ans_header[2], ans_header[3]]);
                let ttl = u32::from_be_bytes([
                    ans_header[4],
                    ans_header[5],
                    ans_header[6],
                    ans_header[7],
                ]);
                let rdlength = u16::from_be_bytes([ans_header[8], ans_header[9]]);
                pos += 10;

                let rdata_start = pos;
                let rdata_end = pos + rdlength as usize;

                let rdata = data
                    .get(rdata_start..rdata_end)
                    .context("DNS answer rdata out of bounds")?;
                pos = rdata_end;

                let rdata_parsed = match rtype {
                    1 if rdata.len() >= 4 => DnsRdata::A {
                        ipv4: format!("{}.{}.{}.{}", rdata[0], rdata[1], rdata[2], rdata[3]),
                    },
                    5 => {
                        let (cname, _) = decode_domain(data, rdata_start)?;
                        DnsRdata::Cname { target: cname }
                    }
                    _ => DnsRdata::Unknown {
                        raw: rdata.to_vec(),
                    },
                };

                answers.push(DnsAnswer {
                    name,
                    record_type: get_type_str(rtype),
                    record_type_raw: rtype,
                    ttl,
                    rdata: rdata_parsed,
                });
            }

            Ok(DnsPacket {
                packet_length: data.len(),
                transaction_id: tx_id,
                flags,
                is_response: qr == 1,
                query_count: qdcount,
                answer_count: ancount,
                return_code: rcode,
                queries,
                answers,
            })
        }

        pub fn dns_decode(dns_request: &[u8]) -> Result<DnsPacket> {
            decode_dns_packet(dns_request)
        }

        // ==========================================
        // TCP Options Decoder
        // ==========================================

        #[derive(Debug, Clone)]
        pub enum TcpOption {
            Nop,
            EndOfOptions,
            Mss(u16),
            WindowScale(u8),
            SackPermitted,
            Sack(Vec<(u32, u32)>),
            Timestamps(u32, u32),
            Unknown { kind: u8, data: Vec<u8> },
        }

        pub fn decode_tcp_options(options: &[u8]) -> Vec<TcpOption> {
            let mut parsed = Vec::new();
            let mut pos = 0;

            while pos < options.len() {
                let kind = options[pos];
                match kind {
                    0 => {
                        parsed.push(TcpOption::EndOfOptions);
                        break;
                    }
                    1 => {
                        parsed.push(TcpOption::Nop);
                        pos += 1;
                    }
                    2 => {
                        if options.len() >= pos + 4 && options[pos + 1] == 4 {
                            let val = u16::from_be_bytes([options[pos + 2], options[pos + 3]]);
                            parsed.push(TcpOption::Mss(val));
                            pos += 4;
                        } else {
                            break;
                        }
                    }
                    3 => {
                        if options.len() >= pos + 3 && options[pos + 1] == 3 {
                            parsed.push(TcpOption::WindowScale(options[pos + 2]));
                            pos += 3;
                        } else {
                            break;
                        }
                    }
                    4 => {
                        if options.len() >= pos + 2 && options[pos + 1] == 2 {
                            parsed.push(TcpOption::SackPermitted);
                            pos += 2;
                        } else {
                            break;
                        }
                    }
                    5 => {
                        if options.len() >= pos + 2 {
                            let len = options[pos + 1] as usize;
                            if options.len() >= pos + len && len >= 2 && (len - 2) % 8 == 0 {
                                let mut blocks = Vec::new();
                                let mut i = pos + 2;
                                while i + 8 <= pos + len {
                                    let left = u32::from_be_bytes([
                                        options[i],
                                        options[i + 1],
                                        options[i + 2],
                                        options[i + 3],
                                    ]);
                                    let right = u32::from_be_bytes([
                                        options[i + 4],
                                        options[i + 5],
                                        options[i + 6],
                                        options[i + 7],
                                    ]);
                                    blocks.push((left, right));
                                    i += 8;
                                }
                                parsed.push(TcpOption::Sack(blocks));
                                pos += len;
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                    8 => {
                        if options.len() >= pos + 10 && options[pos + 1] == 10 {
                            let ts_val = u32::from_be_bytes([
                                options[pos + 2],
                                options[pos + 3],
                                options[pos + 4],
                                options[pos + 5],
                            ]);
                            let ts_ecr = u32::from_be_bytes([
                                options[pos + 6],
                                options[pos + 7],
                                options[pos + 8],
                                options[pos + 9],
                            ]);
                            parsed.push(TcpOption::Timestamps(ts_val, ts_ecr));
                            pos += 10;
                        } else {
                            break;
                        }
                    }
                    _ => {
                        if options.len() > pos + 1 {
                            let len = options[pos + 1] as usize;
                            if len < 2 {
                                break; // 防止死循环
                            }
                            let end = std::cmp::min(pos + len, options.len());
                            parsed.push(TcpOption::Unknown {
                                kind,
                                data: options[pos + 2..end].to_vec(),
                            });
                            pos = end;
                        } else {
                            break;
                        }
                    }
                }
            }
            parsed
        }

        // ==========================================
        // TLS SNI Extractor
        // ==========================================

        #[derive(Debug, Clone)]
        pub struct TlsInfo {
            pub content_type: u8,
            pub version: u16,
            pub sni: Option<String>,
        }

        pub fn decode_tls_sni(payload: &[u8]) -> Result<TlsInfo> {
            if payload.len() < 5 {
                anyhow::bail!("Payload too short to be TLS");
            }

            let content_type = payload[0];
            let version = u16::from_be_bytes([payload[1], payload[2]]);
            let _length = u16::from_be_bytes([payload[3], payload[4]]) as usize;

            let mut sni = None;

            // 如果是 Handshake (0x16) 且是 Client Hello (0x01)
            if content_type == 0x16 && payload.len() > 5 && payload[5] == 0x01 {
                // 快速扫描寻找 SNI 扩展标识: 0x00 0x00
                // 真正严谨的解析应该按层读取长度，这里为了性能和抗畸形单纯做特征搜索
                let mut i = 43; // 跳过 TLS Record(5) + Handshake Header(4) + Client Hello 固定字段(34)

                while i < payload.len().saturating_sub(5) {
                    if payload[i] == 0x00 && payload[i + 1] == 0x00 {
                        if i + 4 < payload.len() {
                            let ext_len =
                                u16::from_be_bytes([payload[i + 2], payload[i + 3]]) as usize;
                            if i + 5 + ext_len <= payload.len() && payload[i + 4] == 0x00 {
                                if i + 6 < payload.len() {
                                    let name_len =
                                        u16::from_be_bytes([payload[i + 5], payload[i + 6]])
                                            as usize;
                                    let name_start = i + 7;
                                    if payload.len() >= name_start + name_len {
                                        sni = Some(
                                            String::from_utf8_lossy(
                                                &payload[name_start..name_start + name_len],
                                            )
                                            .to_string(),
                                        );
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    i += 1;
                }
            }

            Ok(TlsInfo {
                content_type,
                version,
                sni,
            })
        }

        // ==========================================
        // TCP Packet Structure & Decoder
        // ==========================================

        #[derive(Debug, Clone)]
        pub struct TcpPacket<'a> {
            pub src_port: u16,
            pub dst_port: u16,
            pub seq_num: u32,
            pub ack_num: u32,
            pub header_length: usize,
            pub flags: TcpFlags,
            pub window_size: u16,
            pub checksum: u16,
            pub urgent_pointer: u16,
            pub options: &'a [u8],
            pub payload: &'a [u8],

            // 自动深层解析结果
            pub parsed_options: Vec<TcpOption>,
            pub parsed_tls: Option<TlsInfo>,
        }

        #[derive(Debug, Clone, Copy)]
        pub struct TcpFlags {
            pub ns: bool,
            pub cwr: bool,
            pub ece: bool,
            pub urg: bool,
            pub ack: bool,
            pub psh: bool,
            pub rst: bool,
            pub syn: bool,
            pub fin: bool,
        }

        impl TcpFlags {
            pub fn to_short_string(&self) -> String {
                let mut s = String::new();
                if self.fin {
                    s.push('F');
                }
                if self.syn {
                    s.push('S');
                }
                if self.rst {
                    s.push('R');
                }
                if self.psh {
                    s.push('P');
                }

                if s.is_empty() || (self.ack && s.is_empty()) {
                    s.push('.');
                }

                if self.ack && s != "." {
                    s.push('.');
                }
                if self.urg {
                    s.push('U');
                }
                if self.ece {
                    s.push('E');
                }
                if self.cwr {
                    s.push('C');
                }

                format!("[{}]", s)
            }
        }

        pub fn tcp_decode(tcp_request: &[u8]) -> Result<TcpPacket> {
            if tcp_request.len() < 20 {
                anyhow::bail!("TCP packet too short (min 20 bytes)");
            }

            let src_port = u16::from_be_bytes([tcp_request[0], tcp_request[1]]);
            let dst_port = u16::from_be_bytes([tcp_request[2], tcp_request[3]]);
            let seq_num = u32::from_be_bytes([
                tcp_request[4],
                tcp_request[5],
                tcp_request[6],
                tcp_request[7],
            ]);
            let ack_num = u32::from_be_bytes([
                tcp_request[8],
                tcp_request[9],
                tcp_request[10],
                tcp_request[11],
            ]);

            let data_offset_raw = tcp_request[12] >> 4;
            let mut header_length = (data_offset_raw as usize) * 4;

            if header_length < 20 {
                header_length = 20;
            }
            let actual_header_length = std::cmp::min(header_length, tcp_request.len());

            let flags = TcpFlags {
                ns: (tcp_request[12] & 0x01) != 0,
                cwr: (tcp_request[13] & 0x80) != 0,
                ece: (tcp_request[13] & 0x40) != 0,
                urg: (tcp_request[13] & 0x20) != 0,
                ack: (tcp_request[13] & 0x10) != 0,
                psh: (tcp_request[13] & 0x08) != 0,
                rst: (tcp_request[13] & 0x04) != 0,
                syn: (tcp_request[13] & 0x02) != 0,
                fin: (tcp_request[13] & 0x01) != 0,
            };

            let window_size = u16::from_be_bytes([tcp_request[14], tcp_request[15]]);
            let checksum = u16::from_be_bytes([tcp_request[16], tcp_request[17]]);
            let urgent_pointer = u16::from_be_bytes([tcp_request[18], tcp_request[19]]);

            let options = &tcp_request[20..actual_header_length];
            let payload = &tcp_request[actual_header_length..];

            // 执行深层解析
            let parsed_options = decode_tcp_options(options);
            let parsed_tls = decode_tls_sni(payload).ok(); // 如果不是 TLS 或者格式错误，静默忽略设为 None

            Ok(TcpPacket {
                src_port,
                dst_port,
                seq_num,
                ack_num,
                header_length: actual_header_length,
                flags,
                window_size,
                checksum,
                urgent_pointer,
                options,
                payload,
                parsed_options,
                parsed_tls,
            })
        }
    }
}
#[cfg(feature = "ctf")]
pub use ctf::*;
