"""Password authentication utilities."""
import secrets
import hashlib
import hmac
from datetime import datetime, timedelta
from typing import Optional, Tuple

import bcrypt
from loguru import logger


def hash_password(password: str) -> str:
    """Hash a password using bcrypt.

    Args:
        password: Plain text password

    Returns:
        Hashed password string
    """
    # bcrypt automatically handles salting
    salt = bcrypt.gensalt(rounds=12)
    hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
    return hashed.decode('utf-8')


def verify_password(password: str, password_hash: str) -> bool:
    """Verify a password against its hash.

    Args:
        password: Plain text password to verify
        password_hash: Stored hash to compare against

    Returns:
        True if password matches, False otherwise
    """
    try:
        return bcrypt.checkpw(password.encode('utf-8'), password_hash.encode('utf-8'))
    except Exception as e:
        logger.error(f"Password verification error: {e}")
        return False


def generate_verification_token() -> str:
    """Generate a secure email verification token.

    Returns:
        URL-safe token string (64 characters)
    """
    return secrets.token_urlsafe(48)


def generate_invitation_token() -> str:
    """Generate a secure invitation token.

    Returns:
        URL-safe token string (32 characters)
    """
    return secrets.token_urlsafe(24)


def generate_password_reset_token() -> str:
    """Generate a secure password reset token.

    Returns:
        URL-safe token string (64 characters)
    """
    return secrets.token_urlsafe(48)


def get_verification_expiry(hours: int = 24) -> datetime:
    """Get expiry datetime for email verification token.

    Args:
        hours: Number of hours until expiry (default 24)

    Returns:
        Datetime when token expires (timezone-aware UTC)
    """
    from datetime import timezone
    return datetime.now(timezone.utc) + timedelta(hours=hours)


def get_invitation_expiry(days: int = 7) -> datetime:
    """Get expiry datetime for invitation token.

    Args:
        days: Number of days until expiry (default 7)

    Returns:
        Datetime when token expires (timezone-aware UTC)
    """
    from datetime import timezone
    return datetime.now(timezone.utc) + timedelta(days=days)


def is_token_expired(expires_at: datetime) -> bool:
    """Check if a token has expired.

    Args:
        expires_at: Expiry datetime of the token

    Returns:
        True if expired, False otherwise
    """
    from datetime import timezone
    now = datetime.now(timezone.utc)
    # Handle both timezone-aware and naive datetimes
    if expires_at.tzinfo is None:
        expires_at = expires_at.replace(tzinfo=timezone.utc)
    return now > expires_at


def validate_password_strength(password: str) -> Tuple[bool, Optional[str]]:
    """Validate password meets minimum requirements.

    Requirements:
    - Minimum 8 characters
    - At least one uppercase letter
    - At least one lowercase letter
    - At least one digit

    Args:
        password: Password to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if len(password) < 8:
        return False, "Passwort muss mindestens 8 Zeichen lang sein"

    if not any(c.isupper() for c in password):
        return False, "Passwort muss mindestens einen Großbuchstaben enthalten"

    if not any(c.islower() for c in password):
        return False, "Passwort muss mindestens einen Kleinbuchstaben enthalten"

    if not any(c.isdigit() for c in password):
        return False, "Passwort muss mindestens eine Zahl enthalten"

    return True, None
