"""
String Utilities

Common string manipulation functions.
"""

import re
import secrets
import string
import unicodedata
from typing import Optional


def slugify(text: str, max_length: int = 100) -> str:
    """
    Convert text to URL-friendly slug.
    
    Args:
        text: Text to slugify
        max_length: Maximum length of slug
        
    Returns:
        URL-friendly slug
    """
    # Normalize unicode characters
    text = unicodedata.normalize("NFKD", text)
    text = text.encode("ascii", "ignore").decode("ascii")
    
    # Convert to lowercase and replace spaces/special chars with hyphens
    text = re.sub(r"[^\w\s-]", "", text.lower())
    text = re.sub(r"[-\s]+", "-", text).strip("-")
    
    # Truncate to max length
    return text[:max_length]


def truncate(text: str, length: int, suffix: str = "...") -> str:
    """
    Truncate text to specified length.
    
    Args:
        text: Text to truncate
        length: Maximum length
        suffix: Suffix to append if truncated
        
    Returns:
        Truncated text
    """
    if len(text) <= length:
        return text
    return text[: length - len(suffix)] + suffix


def camel_to_snake(text: str) -> str:
    """
    Convert camelCase to snake_case.
    
    Args:
        text: camelCase text
        
    Returns:
        snake_case text
    """
    text = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", text)
    return re.sub("([a-z0-9])([A-Z])", r"\1_\2", text).lower()


def snake_to_camel(text: str, capitalize_first: bool = False) -> str:
    """
    Convert snake_case to camelCase.
    
    Args:
        text: snake_case text
        capitalize_first: Capitalize first letter (PascalCase)
        
    Returns:
        camelCase or PascalCase text
    """
    components = text.split("_")
    if capitalize_first:
        return "".join(x.title() for x in components)
    return components[0] + "".join(x.title() for x in components[1:])


def generate_random_string(
    length: int = 32,
    include_digits: bool = True,
    include_special: bool = False,
) -> str:
    """
    Generate a cryptographically secure random string.
    
    Args:
        length: Length of string
        include_digits: Include digits
        include_special: Include special characters
        
    Returns:
        Random string
    """
    chars = string.ascii_letters
    if include_digits:
        chars += string.digits
    if include_special:
        chars += "!@#$%^&*"
    return "".join(secrets.choice(chars) for _ in range(length))


def mask_email(email: str) -> str:
    """
    Mask email address for privacy.
    
    Args:
        email: Email address
        
    Returns:
        Masked email (e.g., j***@example.com)
    """
    if "@" not in email:
        return "***"
    
    local, domain = email.split("@", 1)
    if len(local) <= 1:
        masked_local = "*"
    elif len(local) <= 3:
        masked_local = local[0] + "*" * (len(local) - 1)
    else:
        masked_local = local[0] + "***" + local[-1]
    
    return f"{masked_local}@{domain}"


def mask_phone(phone: str) -> str:
    """
    Mask phone number for privacy.
    
    Args:
        phone: Phone number
        
    Returns:
        Masked phone (e.g., ***-***-1234)
    """
    # Remove non-digits
    digits = re.sub(r"\D", "", phone)
    
    if len(digits) < 4:
        return "***"
    
    return "*" * (len(digits) - 4) + digits[-4:]


def extract_initials(name: str, max_chars: int = 2) -> str:
    """
    Extract initials from a name.
    
    Args:
        name: Full name
        max_chars: Maximum number of initials
        
    Returns:
        Initials (e.g., "JD" for "John Doe")
    """
    words = name.strip().split()
    initials = [w[0].upper() for w in words if w]
    return "".join(initials[:max_chars])


def normalize_whitespace(text: str) -> str:
    """
    Normalize whitespace in text.
    
    Args:
        text: Input text
        
    Returns:
        Text with normalized whitespace
    """
    return " ".join(text.split())
