"""
Helper Utilities
General purpose helper functions
"""
import secrets
import string
from datetime import datetime
from typing import Optional


def generate_code(length: int = 8, chars: str = None) -> str:
    """Generate a random alphanumeric code"""
    if chars is None:
        chars = string.ascii_uppercase + string.digits
    return "".join(secrets.choice(chars) for _ in range(length))


def generate_numeric_code(length: int = 6) -> str:
    """Generate a random numeric code (for OTP)"""
    return "".join(secrets.choice(string.digits) for _ in range(length))


def format_currency(amount_cents: int, currency: str = "USD") -> str:
    """Format cents to currency string"""
    amount = amount_cents / 100
    if currency == "USD":
        return f"${amount:,.2f}"
    elif currency == "EUR":
        return f"€{amount:,.2f}"
    elif currency == "GBP":
        return f"£{amount:,.2f}"
    elif currency == "INR":
        return f"₹{amount:,.2f}"
    return f"{amount:,.2f} {currency}"


def parse_currency(amount_str: str) -> int:
    """Parse currency string to cents"""
    # Remove currency symbols and commas
    cleaned = amount_str.replace("$", "").replace("€", "").replace("£", "").replace("₹", "").replace(",", "").strip()
    return int(float(cleaned) * 100)


def mask_phone(phone: str) -> str:
    """Mask phone number for privacy"""
    if len(phone) <= 4:
        return phone
    return phone[:3] + "*" * (len(phone) - 6) + phone[-3:]


def mask_email(email: str) -> str:
    """Mask email for privacy"""
    parts = email.split("@")
    if len(parts) != 2:
        return email
    username = parts[0]
    domain = parts[1]
    if len(username) <= 2:
        masked_username = username[0] + "*"
    else:
        masked_username = username[0] + "*" * (len(username) - 2) + username[-1]
    return f"{masked_username}@{domain}"


def mask_account_number(account: str) -> str:
    """Mask bank account number"""
    if len(account) <= 4:
        return account
    return "*" * (len(account) - 4) + account[-4:]


def calculate_age(birth_date: datetime) -> int:
    """Calculate age from birth date"""
    today = datetime.today()
    age = today.year - birth_date.year
    if (today.month, today.day) < (birth_date.month, birth_date.day):
        age -= 1
    return age


def format_distance(km: float) -> str:
    """Format distance for display"""
    if km < 1:
        return f"{int(km * 1000)} m"
    return f"{km:.1f} km"


def format_duration(minutes: int) -> str:
    """Format duration for display"""
    if minutes < 60:
        return f"{minutes} min"
    hours = minutes // 60
    mins = minutes % 60
    if mins == 0:
        return f"{hours} hr"
    return f"{hours} hr {mins} min"


def format_datetime(dt: datetime, format_str: str = "%b %d, %Y %I:%M %p") -> str:
    """Format datetime for display"""
    return dt.strftime(format_str)


def get_greeting() -> str:
    """Get time-based greeting"""
    hour = datetime.now().hour
    if hour < 12:
        return "Good morning"
    elif hour < 17:
        return "Good afternoon"
    else:
        return "Good evening"


def build_order_by(model_or_col, sort_by: str, order: str, allowed: set):
    """
    Build SQLAlchemy order_by clause for paginated queries.
    Returns (query_method, column) - apply via query.order_by(result).
    sort_by defaults to 'created_at', order to 'desc'.
    """
    from sqlalchemy import asc, desc

    if sort_by not in allowed:
        sort_by = "created_at"
    if order not in ("asc", "desc"):
        order = "desc"
    col = getattr(model_or_col, sort_by, None) if hasattr(model_or_col, sort_by) else None
    if col is None:
        col = getattr(model_or_col, "created_at", model_or_col)
    return desc(col) if order == "desc" else asc(col)
