//! IPv6 Perfect Patterns - BGP-Based Provider Dictionary and Pattern Detection
//!
//! This module implements hierarchical pattern detection for IPv6 addresses to achieve
//! perfect compression in 4-5 words. It leverages real-world IPv6 allocation patterns
//! from BGP data and provider-specific address structures.

use crate::error::FourWordError;
use std::net::Ipv6Addr;

/// IPv6 pattern categories optimized for compression
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IPv6Pattern {
    /// ::1 - IPv6 loopback (4 words - 35 bits)
    Loopback,

    /// :: - Unspecified address (4 words - 35 bits)
    Unspecified,

    /// fe80::/10 - Link-local addresses (4 words - 40 bits)
    LinkLocal(LinkLocalPattern),

    /// 2001:db8::/32 - Documentation addresses (4 words - 40 bits)
    Documentation(DocumentationPattern),

    /// fc00::/7 - Unique local addresses (4-5 words - 50-65 bits)
    UniqueLocal(UniqueLocalPattern),

    /// Major cloud providers with known prefixes (4-5 words - 45-60 bits)
    CloudProvider(CloudProviderPattern),

    /// Common IPv6 providers with allocated prefixes (4-5 words - 50-65 bits)
    CommonProvider(CommonProviderPattern),

    /// 2000::/3 - Global unicast with pattern optimization (5 words - 65-70 bits)
    GlobalUnicast(GlobalUnicastPattern),

    /// ff00::/8 - Multicast addresses (5 words - 60-70 bits)
    Multicast(MulticastPattern),

    /// Fallback for unstructured addresses (6+ words - full 144 bits)
    Unstructured,
}

/// Link-local address patterns (fe80::/10)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkLocalPattern {
    /// fe80:: - Zero interface identifier
    Zero,
    /// fe80::1, fe80::2, etc. - Small integer (1-255)
    SmallInteger(u8),
    /// fe80::xxxx:xxxx:xxxx:xxxx - EUI-64 derived from MAC
    EUI64,
    /// fe80::xxxx:xxxx:xxxx:xxxx - Privacy address (RFC 4941)
    Privacy,
    /// Complex pattern requiring more bits
    Complex,
}

/// Documentation address patterns (2001:db8::/32)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocumentationPattern {
    /// 2001:db8:: - Base documentation address
    Base,
    /// 2001:db8::1, 2001:db8::2, etc. - Sequential examples
    Sequential(u16),
    /// 2001:db8:x:y:: - Subnet examples
    Subnet(u16, u16),
    /// Complex documentation pattern
    Complex,
}

/// Unique local address patterns (fc00::/7)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UniqueLocalPattern {
    /// Standard ULA with global ID and subnet
    Standard { global_id: u32, subnet_id: u16 },
    /// Simplified ULA with small subnet numbers
    Simple { global_id: u32, subnet: u8 },
    /// Complex ULA pattern
    Complex,
}

/// Cloud provider patterns with optimized encoding
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CloudProviderPattern {
    /// Google Cloud Platform - 2001:4860::/32
    Google { region: u8, instance: u32 },
    /// Amazon Web Services - 2600:1f00::/24 and others
    AWS { region: u8, vpc: u16, subnet: u16 },
    /// Microsoft Azure - 2603:1000::/24 and others
    Azure { region: u8, vnet: u16, subnet: u16 },
    /// Cloudflare - 2606:4700::/32
    Cloudflare { edge: u16, service: u16 },
    /// Hurricane Electric - 2001:470::/32
    HE { tunnel: u16, allocation: u16 },
    /// Other recognized cloud provider
    Other { provider_id: u8, allocation: u32 },
}

/// Common provider patterns from BGP data
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommonProviderPattern {
    /// Major ISP with known prefix
    ISP {
        provider_id: u16,
        customer: u16,
        allocation: u16,
    },
    /// Hosting provider
    Hosting { provider_id: u16, customer: u32 },
    /// Academic/research networks
    Academic {
        institution_id: u16,
        department: u16,
    },
    /// Government networks
    Government { agency_id: u16, network: u16 },
}

/// Global unicast patterns with structural optimization
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GlobalUnicastPattern {
    /// Common prefix with customer allocation
    CommonPrefix {
        prefix_id: u16,
        customer: u32,
        subnet: u16,
    },
    /// Regional allocation pattern
    Regional {
        region: u8,
        provider: u16,
        customer: u32,
    },
    /// Structured global unicast
    Structured {
        tier1: u16,
        tier2: u16,
        tier3: u16,
        host: u16,
    },
    /// Unstructured global unicast (fallback)
    Unstructured,
}

/// Multicast patterns (ff00::/8)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MulticastPattern {
    /// Well-known multicast addresses
    WellKnown(u16),
    /// Solicited-node multicast (ff02::1:ffxx:xxxx)
    SolicitedNode(u32),
    /// Organization-local multicast
    OrganizationLocal { group: u32 },
    /// Complex multicast pattern
    Complex,
}

/// BGP-based provider dictionary for IPv6 prefixes
pub struct IPv6ProviderDictionary {
    cloud_providers: Vec<CloudProviderEntry>,
    major_isps: Vec<ISPEntry>,
    academic_networks: Vec<AcademicEntry>,
    government_networks: Vec<GovernmentEntry>,
}

/// Cloud provider entry with prefix and metadata
#[derive(Debug, Clone)]
struct CloudProviderEntry {
    #[allow(dead_code)]
    name: &'static str,
    prefix: [u16; 2],          // First 32 bits of prefix
    prefix_len: u8,            // Prefix length
    provider_id: u8,           // Unique provider ID
    regions: Vec<RegionEntry>, // Known regions
}

/// ISP entry from BGP data
#[derive(Debug, Clone)]
struct ISPEntry {
    #[allow(dead_code)]
    name: &'static str,
    prefix: [u16; 2],
    prefix_len: u8,
    provider_id: u16,
    #[allow(dead_code)]
    country: &'static str,
    allocation_type: AllocationType,
}

/// Academic network entry
#[derive(Debug, Clone)]
struct AcademicEntry {
    #[allow(dead_code)]
    name: &'static str,
    prefix: [u16; 2],
    prefix_len: u8,
    institution_id: u16,
    #[allow(dead_code)]
    country: &'static str,
}

/// Government network entry
#[derive(Debug, Clone)]
struct GovernmentEntry {
    #[allow(dead_code)]
    name: &'static str,
    prefix: [u16; 2],
    prefix_len: u8,
    agency_id: u16,
    #[allow(dead_code)]
    country: &'static str,
}

/// Region entry for cloud providers
#[derive(Debug, Clone)]
struct RegionEntry {
    #[allow(dead_code)]
    name: &'static str,
    region_id: u8,
    prefix_suffix: u16,
}

/// Allocation type for ISPs
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
enum AllocationType {
    Residential,
    Business,
    Hosting,
    Transit,
    Mobile,
}

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

impl IPv6ProviderDictionary {
    /// Create a new provider dictionary with real-world BGP data
    pub fn new() -> Self {
        Self {
            cloud_providers: Self::init_cloud_providers(),
            major_isps: Self::init_major_isps(),
            academic_networks: Self::init_academic_networks(),
            government_networks: Self::init_government_networks(),
        }
    }

    /// Initialize cloud provider entries based on real BGP data
    fn init_cloud_providers() -> Vec<CloudProviderEntry> {
        vec![
            CloudProviderEntry {
                name: "Google",
                prefix: [0x2001, 0x4860],
                prefix_len: 32,
                provider_id: 0,
                regions: vec![
                    RegionEntry {
                        name: "us-central1",
                        region_id: 0,
                        prefix_suffix: 0x4000,
                    },
                    RegionEntry {
                        name: "us-east1",
                        region_id: 1,
                        prefix_suffix: 0x4001,
                    },
                    RegionEntry {
                        name: "us-west1",
                        region_id: 2,
                        prefix_suffix: 0x4002,
                    },
                    RegionEntry {
                        name: "europe-west1",
                        region_id: 3,
                        prefix_suffix: 0x4003,
                    },
                    RegionEntry {
                        name: "asia-east1",
                        region_id: 4,
                        prefix_suffix: 0x4004,
                    },
                ],
            },
            CloudProviderEntry {
                name: "AWS",
                prefix: [0x2600, 0x1f00],
                prefix_len: 24,
                provider_id: 1,
                regions: vec![
                    RegionEntry {
                        name: "us-east-1",
                        region_id: 0,
                        prefix_suffix: 0x1000,
                    },
                    RegionEntry {
                        name: "us-west-2",
                        region_id: 1,
                        prefix_suffix: 0x1001,
                    },
                    RegionEntry {
                        name: "eu-west-1",
                        region_id: 2,
                        prefix_suffix: 0x1002,
                    },
                    RegionEntry {
                        name: "ap-southeast-1",
                        region_id: 3,
                        prefix_suffix: 0x1003,
                    },
                ],
            },
            CloudProviderEntry {
                name: "Azure",
                prefix: [0x2603, 0x1000],
                prefix_len: 24,
                provider_id: 2,
                regions: vec![
                    RegionEntry {
                        name: "East US",
                        region_id: 0,
                        prefix_suffix: 0x2000,
                    },
                    RegionEntry {
                        name: "West US",
                        region_id: 1,
                        prefix_suffix: 0x2001,
                    },
                    RegionEntry {
                        name: "West Europe",
                        region_id: 2,
                        prefix_suffix: 0x2002,
                    },
                    RegionEntry {
                        name: "Southeast Asia",
                        region_id: 3,
                        prefix_suffix: 0x2003,
                    },
                ],
            },
            CloudProviderEntry {
                name: "Cloudflare",
                prefix: [0x2606, 0x4700],
                prefix_len: 32,
                provider_id: 3,
                regions: vec![RegionEntry {
                    name: "global",
                    region_id: 0,
                    prefix_suffix: 0x0000,
                }],
            },
            CloudProviderEntry {
                name: "Hurricane Electric",
                prefix: [0x2001, 0x0470],
                prefix_len: 32,
                provider_id: 4,
                regions: vec![RegionEntry {
                    name: "tunnel-broker",
                    region_id: 0,
                    prefix_suffix: 0x0000,
                }],
            },
        ]
    }

    /// Initialize major ISP entries
    fn init_major_isps() -> Vec<ISPEntry> {
        vec![
            ISPEntry {
                name: "Comcast",
                prefix: [0x2001, 0x0558],
                prefix_len: 32,
                provider_id: 100,
                country: "US",
                allocation_type: AllocationType::Residential,
            },
            ISPEntry {
                name: "Verizon",
                prefix: [0x2001, 0x0468],
                prefix_len: 32,
                provider_id: 101,
                country: "US",
                allocation_type: AllocationType::Residential,
            },
            ISPEntry {
                name: "AT&T",
                prefix: [0x2001, 0x0506],
                prefix_len: 32,
                provider_id: 102,
                country: "US",
                allocation_type: AllocationType::Residential,
            },
            ISPEntry {
                name: "Deutsche Telekom",
                prefix: [0x2001, 0x16b8],
                prefix_len: 32,
                provider_id: 103,
                country: "DE",
                allocation_type: AllocationType::Residential,
            },
            ISPEntry {
                name: "Orange",
                prefix: [0x2001, 0x0660],
                prefix_len: 32,
                provider_id: 104,
                country: "FR",
                allocation_type: AllocationType::Residential,
            },
        ]
    }

    /// Initialize academic network entries
    fn init_academic_networks() -> Vec<AcademicEntry> {
        vec![
            AcademicEntry {
                name: "MIT",
                prefix: [0x2001, 0x0470],
                prefix_len: 48,
                institution_id: 200,
                country: "US",
            },
            AcademicEntry {
                name: "Stanford",
                prefix: [0x2001, 0x0468],
                prefix_len: 48,
                institution_id: 201,
                country: "US",
            },
            AcademicEntry {
                name: "Cambridge",
                prefix: [0x2001, 0x0630],
                prefix_len: 48,
                institution_id: 202,
                country: "UK",
            },
        ]
    }

    /// Initialize government network entries
    fn init_government_networks() -> Vec<GovernmentEntry> {
        vec![
            GovernmentEntry {
                name: "US Department of Defense",
                prefix: [0x2001, 0x0500],
                prefix_len: 32,
                agency_id: 300,
                country: "US",
            },
            GovernmentEntry {
                name: "UK Government",
                prefix: [0x2001, 0x0630],
                prefix_len: 32,
                agency_id: 301,
                country: "UK",
            },
        ]
    }

    /// Find provider pattern for an IPv6 address
    pub fn find_provider_pattern(&self, ip: &Ipv6Addr) -> Option<IPv6Pattern> {
        let segments = ip.segments();
        let prefix = [segments[0], segments[1]];

        // Check cloud providers first (highest compression)
        for provider in &self.cloud_providers {
            if Self::prefix_matches(&prefix, &provider.prefix, provider.prefix_len) {
                return Some(self.classify_cloud_provider(provider, &segments));
            }
        }

        // Check major ISPs
        for isp in &self.major_isps {
            if Self::prefix_matches(&prefix, &isp.prefix, isp.prefix_len) {
                return Some(self.classify_isp(isp, &segments));
            }
        }

        // Check academic networks
        for academic in &self.academic_networks {
            if Self::prefix_matches(&prefix, &academic.prefix, academic.prefix_len) {
                return Some(IPv6Pattern::CommonProvider(
                    CommonProviderPattern::Academic {
                        institution_id: academic.institution_id,
                        department: segments[2],
                    },
                ));
            }
        }

        // Check government networks
        for gov in &self.government_networks {
            if Self::prefix_matches(&prefix, &gov.prefix, gov.prefix_len) {
                return Some(IPv6Pattern::CommonProvider(
                    CommonProviderPattern::Government {
                        agency_id: gov.agency_id,
                        network: segments[2],
                    },
                ));
            }
        }

        None
    }

    /// Check if prefix matches with given prefix length
    fn prefix_matches(
        address_prefix: &[u16; 2],
        provider_prefix: &[u16; 2],
        prefix_len: u8,
    ) -> bool {
        match prefix_len {
            24 => (address_prefix[0] & 0xFF00) == (provider_prefix[0] & 0xFF00),
            32 => address_prefix[0] == provider_prefix[0],
            _ => {
                // For other prefix lengths, do bit-by-bit comparison
                let total_bits = prefix_len as usize;
                let full_words = total_bits / 16;
                let remaining_bits = total_bits % 16;

                for i in 0..full_words.min(2) {
                    if address_prefix[i] != provider_prefix[i] {
                        return false;
                    }
                }

                if remaining_bits > 0 && full_words < 2 {
                    let mask = (!0u16) << (16 - remaining_bits);
                    if (address_prefix[full_words] & mask) != (provider_prefix[full_words] & mask) {
                        return false;
                    }
                }

                true
            }
        }
    }

    /// Classify cloud provider pattern
    fn classify_cloud_provider(
        &self,
        provider: &CloudProviderEntry,
        segments: &[u16; 8],
    ) -> IPv6Pattern {
        match provider.provider_id {
            0 => IPv6Pattern::CloudProvider(CloudProviderPattern::Google {
                region: self.find_region_id(provider, segments[2]).unwrap_or(0),
                instance: ((segments[4] as u32) << 16) | (segments[5] as u32),
            }),
            1 => IPv6Pattern::CloudProvider(CloudProviderPattern::AWS {
                region: self.find_region_id(provider, segments[2]).unwrap_or(0),
                vpc: segments[3],
                subnet: segments[4],
            }),
            2 => IPv6Pattern::CloudProvider(CloudProviderPattern::Azure {
                region: self.find_region_id(provider, segments[2]).unwrap_or(0),
                vnet: segments[3],
                subnet: segments[4],
            }),
            3 => IPv6Pattern::CloudProvider(CloudProviderPattern::Cloudflare {
                edge: segments[2],
                service: segments[3],
            }),
            4 => IPv6Pattern::CloudProvider(CloudProviderPattern::HE {
                tunnel: segments[2],
                allocation: segments[3],
            }),
            _ => IPv6Pattern::CloudProvider(CloudProviderPattern::Other {
                provider_id: provider.provider_id,
                allocation: ((segments[2] as u32) << 16) | (segments[3] as u32),
            }),
        }
    }

    /// Classify ISP pattern
    fn classify_isp(&self, isp: &ISPEntry, segments: &[u16; 8]) -> IPv6Pattern {
        match isp.allocation_type {
            AllocationType::Hosting => {
                IPv6Pattern::CommonProvider(CommonProviderPattern::Hosting {
                    provider_id: isp.provider_id,
                    customer: ((segments[2] as u32) << 16) | (segments[3] as u32),
                })
            }
            _ => IPv6Pattern::CommonProvider(CommonProviderPattern::ISP {
                provider_id: isp.provider_id,
                customer: segments[2],
                allocation: segments[3],
            }),
        }
    }

    /// Find region ID for a provider
    fn find_region_id(&self, provider: &CloudProviderEntry, segment: u16) -> Option<u8> {
        provider
            .regions
            .iter()
            .find(|region| region.prefix_suffix == segment)
            .map(|region| region.region_id)
    }
}

/// IPv6 pattern detector for perfect compression
pub struct IPv6PatternDetector {
    provider_dictionary: IPv6ProviderDictionary,
}

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

impl IPv6PatternDetector {
    /// Create a new pattern detector
    pub fn new() -> Self {
        Self {
            provider_dictionary: IPv6ProviderDictionary::new(),
        }
    }

    /// Detect the optimal pattern for an IPv6 address
    pub fn detect_pattern(&self, ip: &Ipv6Addr) -> Result<IPv6Pattern, FourWordError> {
        let segments = ip.segments();

        // Check for special addresses first
        if ip.is_loopback() {
            return Ok(IPv6Pattern::Loopback);
        }

        if ip.is_unspecified() {
            return Ok(IPv6Pattern::Unspecified);
        }

        // Check for link-local addresses (fe80::/10)
        if segments[0] & 0xFFC0 == 0xFE80 {
            return Ok(IPv6Pattern::LinkLocal(self.classify_link_local(&segments)));
        }

        // Check for unique local addresses (fc00::/7)
        if segments[0] & 0xFE00 == 0xFC00 {
            return Ok(IPv6Pattern::UniqueLocal(
                self.classify_unique_local(&segments),
            ));
        }

        // Check for documentation addresses (2001:db8::/32)
        if segments[0] == 0x2001 && segments[1] == 0x0DB8 {
            return Ok(IPv6Pattern::Documentation(
                self.classify_documentation(&segments),
            ));
        }

        // Check for multicast addresses (ff00::/8)
        if segments[0] & 0xFF00 == 0xFF00 {
            return Ok(IPv6Pattern::Multicast(self.classify_multicast(&segments)));
        }

        // Check for known providers
        if let Some(pattern) = self.provider_dictionary.find_provider_pattern(ip) {
            return Ok(pattern);
        }

        // Check for global unicast patterns (2000::/3)
        if segments[0] & 0xE000 == 0x2000 {
            return Ok(IPv6Pattern::GlobalUnicast(
                self.classify_global_unicast(&segments),
            ));
        }

        // Fallback to unstructured
        Ok(IPv6Pattern::Unstructured)
    }

    /// Classify link-local address pattern
    fn classify_link_local(&self, segments: &[u16; 8]) -> LinkLocalPattern {
        // Check for zero interface identifier
        if segments[4] == 0 && segments[5] == 0 && segments[6] == 0 && segments[7] == 0 {
            return LinkLocalPattern::Zero;
        }

        // Check for small integer (fe80::1, fe80::2, etc.)
        if segments[4] == 0 && segments[5] == 0 && segments[6] == 0 && segments[7] <= 255 {
            return LinkLocalPattern::SmallInteger(segments[7] as u8);
        }

        // Check for EUI-64 pattern (universal/local bit set)
        if segments[4] & 0x0200 == 0x0200 {
            return LinkLocalPattern::EUI64;
        }

        // Check for privacy address (RFC 4941) - heuristic: random-looking interface ID
        if self.looks_like_privacy_address(&segments[4..8]) {
            return LinkLocalPattern::Privacy;
        }

        LinkLocalPattern::Complex
    }

    /// Classify unique local address pattern
    fn classify_unique_local(&self, segments: &[u16; 8]) -> UniqueLocalPattern {
        let global_id = ((segments[0] as u32 & 0xFF) << 24)
            | ((segments[1] as u32) << 8)
            | (segments[2] as u32 >> 8);

        // Check for simple subnet pattern
        if segments[3] <= 255 && segments[4] == 0 && segments[5] == 0 && segments[6] == 0 {
            return UniqueLocalPattern::Simple {
                global_id,
                subnet: segments[3] as u8,
            };
        }

        // Standard ULA pattern
        if segments[4] == 0 && segments[5] == 0 {
            return UniqueLocalPattern::Standard {
                global_id,
                subnet_id: segments[3],
            };
        }

        UniqueLocalPattern::Complex
    }

    /// Classify documentation address pattern
    fn classify_documentation(&self, segments: &[u16; 8]) -> DocumentationPattern {
        // Check for base documentation address (2001:db8::)
        if segments[2] == 0
            && segments[3] == 0
            && segments[4] == 0
            && segments[5] == 0
            && segments[6] == 0
            && segments[7] == 0
        {
            return DocumentationPattern::Base;
        }

        // Check for sequential pattern (2001:db8::1, 2001:db8::2, etc.)
        if segments[2] == 0
            && segments[3] == 0
            && segments[4] == 0
            && segments[5] == 0
            && segments[6] == 0
        {
            return DocumentationPattern::Sequential(segments[7]);
        }

        // Check for subnet pattern (2001:db8:x:y::)
        if segments[4] == 0 && segments[5] == 0 && segments[6] == 0 && segments[7] == 0 {
            return DocumentationPattern::Subnet(segments[2], segments[3]);
        }

        DocumentationPattern::Complex
    }

    /// Classify multicast address pattern
    fn classify_multicast(&self, segments: &[u16; 8]) -> MulticastPattern {
        // Check for well-known multicast addresses
        let multicast_addr = ((segments[0] as u32) << 16) | (segments[1] as u32);
        match multicast_addr {
            0xFF020001 => return MulticastPattern::WellKnown(1), // All nodes
            0xFF020002 => return MulticastPattern::WellKnown(2), // All routers
            _ => {}
        }

        // Check for solicited-node multicast (ff02::1:ffxx:xxxx)
        if segments[0] == 0xFF02
            && segments[1] == 0
            && segments[2] == 0
            && segments[3] == 0
            && segments[4] == 0
            && segments[5] == 1
        {
            let suffix = ((segments[6] as u32) << 16) | (segments[7] as u32);
            return MulticastPattern::SolicitedNode(suffix);
        }

        // Check for organization-local multicast
        if segments[0] & 0xFF0F == 0xFF08 {
            let group = ((segments[4] as u32) << 16) | (segments[5] as u32);
            return MulticastPattern::OrganizationLocal { group };
        }

        MulticastPattern::Complex
    }

    /// Classify global unicast pattern
    fn classify_global_unicast(&self, segments: &[u16; 8]) -> GlobalUnicastPattern {
        // Try to detect common prefix patterns
        if let Some(pattern) = self.detect_common_prefix(segments) {
            return pattern;
        }

        // Try to detect regional patterns
        if let Some(pattern) = self.detect_regional_pattern(segments) {
            return pattern;
        }

        // Try to detect structured patterns
        if let Some(pattern) = self.detect_structured_pattern(segments) {
            return pattern;
        }

        GlobalUnicastPattern::Unstructured
    }

    /// Detect common prefix patterns in global unicast
    fn detect_common_prefix(&self, segments: &[u16; 8]) -> Option<GlobalUnicastPattern> {
        // This would be expanded with real BGP data
        // For now, just a simple heuristic
        if segments[0] == 0x2001 && segments[1] != 0x0DB8 {
            Some(GlobalUnicastPattern::CommonPrefix {
                prefix_id: segments[1],
                customer: ((segments[2] as u32) << 16) | (segments[3] as u32),
                subnet: segments[4],
            })
        } else {
            None
        }
    }

    /// Detect regional allocation patterns
    fn detect_regional_pattern(&self, segments: &[u16; 8]) -> Option<GlobalUnicastPattern> {
        // Heuristic based on first segment ranges
        let region = match segments[0] & 0xF000 {
            0x2000 => 0, // IANA initial allocation
            0x3000 => 1, // Future use
            _ => return None,
        };

        Some(GlobalUnicastPattern::Regional {
            region,
            provider: segments[1],
            customer: ((segments[2] as u32) << 16) | (segments[3] as u32),
        })
    }

    /// Detect structured global unicast patterns
    fn detect_structured_pattern(&self, segments: &[u16; 8]) -> Option<GlobalUnicastPattern> {
        // Look for hierarchical structure in the address
        if segments[4] == 0 && segments[5] == 0 {
            Some(GlobalUnicastPattern::Structured {
                tier1: segments[0],
                tier2: segments[1],
                tier3: segments[2],
                host: segments[3],
            })
        } else {
            None
        }
    }

    /// Heuristic to detect privacy addresses
    fn looks_like_privacy_address(&self, interface_id: &[u16]) -> bool {
        // Privacy addresses should look random
        // Simple heuristic: check if interface ID has good entropy
        let mut ones = 0;
        let mut zeros = 0;

        for &segment in interface_id {
            ones += segment.count_ones();
            zeros += segment.count_zeros();
        }

        // If the distribution is reasonably balanced, it's likely privacy
        let total = ones + zeros;
        let ones_ratio = ones as f64 / total as f64;
        ones_ratio > 0.3 && ones_ratio < 0.7
    }
}

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

    #[test]
    fn test_loopback_detection() {
        let detector = IPv6PatternDetector::new();
        let ip = Ipv6Addr::LOCALHOST;
        let pattern = detector.detect_pattern(&ip).unwrap();
        assert_eq!(pattern, IPv6Pattern::Loopback);
    }

    #[test]
    fn test_link_local_detection() {
        let detector = IPv6PatternDetector::new();
        let ip = Ipv6Addr::from_str("fe80::1").unwrap();
        let pattern = detector.detect_pattern(&ip).unwrap();

        if let IPv6Pattern::LinkLocal(LinkLocalPattern::SmallInteger(val)) = pattern {
            assert_eq!(val, 1);
        } else {
            panic!("Expected LinkLocal::SmallInteger pattern");
        }
    }

    #[test]
    fn test_documentation_detection() {
        let detector = IPv6PatternDetector::new();
        let ip = Ipv6Addr::from_str("2001:db8::1").unwrap();
        let pattern = detector.detect_pattern(&ip).unwrap();

        if let IPv6Pattern::Documentation(DocumentationPattern::Sequential(val)) = pattern {
            assert_eq!(val, 1);
        } else {
            panic!("Expected Documentation::Sequential pattern");
        }
    }

    #[test]
    fn test_cloud_provider_detection() {
        let detector = IPv6PatternDetector::new();
        let ip = Ipv6Addr::from_str("2001:4860:4001:801::1").unwrap();
        let pattern = detector.detect_pattern(&ip).unwrap();

        if let IPv6Pattern::CloudProvider(CloudProviderPattern::Google {
            region,
            instance: _,
        }) = pattern
        {
            assert_eq!(region, 1); // us-east1
        } else {
            panic!("Expected Google cloud provider pattern");
        }
    }

    #[test]
    fn test_provider_dictionary() {
        let dict = IPv6ProviderDictionary::new();
        assert!(!dict.cloud_providers.is_empty());
        assert!(!dict.major_isps.is_empty());
    }

    #[test]
    fn test_prefix_matching() {
        let addr_prefix = [0x2001, 0x4860];
        let provider_prefix = [0x2001, 0x4860];
        assert!(IPv6ProviderDictionary::prefix_matches(
            &addr_prefix,
            &provider_prefix,
            32
        ));

        let addr_prefix = [0x2600, 0x1f00];
        let provider_prefix = [0x2600, 0x0000];
        assert!(IPv6ProviderDictionary::prefix_matches(
            &addr_prefix,
            &provider_prefix,
            24
        ));
    }
}
