"""Utility functions for the ECP Auth package.

Provides helper functions for certificate formatting, session
key management, and logging configuration.
"""

from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Any

from django.contrib.auth import get_user_model
from django.http import HttpRequest

from ecp_auth.settings import get_session_key_prefix

logger: logging.Logger = logging.getLogger(__name__)


def get_session_key(name: str) -> str:
    """Build a prefixed session key for ECP Auth data.

    Args:
        name: The session key name (without prefix).

    Returns:
        Prefixed session key string.

    Example:
        >>> get_session_key("challenge")
        'ecp_auth_challenge'
    """
    prefix: str = get_session_key_prefix()
    return f"{prefix}{name}"


def store_in_session(request: HttpRequest, key: str, value: Any) -> None:
    """Store a value in the session using the ECP Auth key prefix.

    Args:
        request: The HTTP request object with session.
        key: Session key name (without prefix).
        value: Value to store in the session.
    """
    session_key: str = get_session_key(key)
    request.session[session_key] = value
    request.session.modified = True
    logger.debug("Stored session data: %s", session_key)


def get_from_session(request: HttpRequest, key: str, default: Any = None) -> Any:
    """Retrieve a value from the session using the ECP Auth key prefix.

    Args:
        request: The HTTP request object with session.
        key: Session key name (without prefix).
        default: Default value if the key is not found.

    Returns:
        The stored value or the default.
    """
    session_key: str = get_session_key(key)
    return request.session.get(session_key, default)


def remove_from_session(request: HttpRequest, key: str) -> None:
    """Remove a value from the session.

    Args:
        request: The HTTP request object with session.
        key: Session key name (without prefix).
    """
    session_key: str = get_session_key(key)
    if session_key in request.session:
        del request.session[session_key]
        request.session.modified = True
        logger.debug("Removed session data: %s", session_key)


def clear_ecp_session(request: HttpRequest) -> None:
    """Clear all ECP Auth data from the session.

    Removes all session keys that start with the ECP Auth prefix.

    Args:
        request: The HTTP request object with session.
    """
    prefix: str = get_session_key_prefix()
    keys_to_remove: list[str] = [
        key for key in request.session.keys()
        if key.startswith(prefix)
    ]

    for key in keys_to_remove:
        del request.session[key]

    if keys_to_remove:
        request.session.modified = True
        logger.debug(
            "Cleared %d ECP session keys.", len(keys_to_remove)
        )


def format_certificate_dn(dn: str) -> dict[str, str]:
    """Parse an RFC 4514 distinguished name into a dictionary.

    Args:
        dn: The distinguished name string (e.g., ``CN=User,O=Org``).

    Returns:
        Dictionary mapping attribute types to values.

    Example:
        >>> format_certificate_dn("CN=John Doe,O=Example Corp")
        {'CN': 'John Doe', 'O': 'Example Corp'}
    """
    result: dict[str, str] = {}
    if not dn:
        return result

    parts: list[str] = []
    current: str = ""

    for char in dn:
        if char == "," and not current.endswith("\\"):
            parts.append(current.strip())
            current = ""
        else:
            current += char

    if current.strip():
        parts.append(current.strip())

    for part in parts:
        if "=" in part:
            key, _, value = part.partition("=")
            result[key.strip()] = value.strip()

    return result


def get_client_ip(request: HttpRequest) -> str:
    """Extract the client IP address from the request.

    Checks ``X-Forwarded-For`` header first (for proxied requests),
    then falls back to ``REMOTE_ADDR``.

    Args:
        request: The HTTP request object.

    Returns:
        Client IP address as a string.
    """
    x_forwarded_for: str | None = request.META.get("HTTP_X_FORWARDED_FOR")
    if x_forwarded_for:
        return x_forwarded_for.split(",")[0].strip()
    return request.META.get("REMOTE_ADDR", "unknown")


def utc_now() -> datetime:
    """Get the current UTC datetime (timezone-aware).

    Returns:
        Current UTC datetime.
    """
    return datetime.now(timezone.utc)
