"""
Root auth provider: base settings and interface common to all auth methods.
"""
from __future__ import annotations

import hmac
import secrets
import time
from datetime import timedelta


class RootAuthProvider:
    """
    Base auth provider with admin credentials, session timeout, and session create/validate.
    Subclass or use as-is for simple admin user/password auth.
    """

    def __init__(
        self,
        *,
        admin_user: bytes | None = None,
        admin_password: bytes | None = None,
        session_timeout: timedelta | float | None = None,  # duration; None = no expiry
    ) -> None:
        """
        admin_user: optional admin username (bytes). If None, no admin login is accepted.
        admin_password: optional admin password (bytes). If None, no admin login is accepted.
        session_timeout: optional duration in seconds (float) or timedelta. If None, sessions do not expire.
        """
        self.admin_user = admin_user
        self.admin_password = admin_password
        if session_timeout is not None and hasattr(session_timeout, "total_seconds"):
            self._timeout_seconds = session_timeout.total_seconds()
        else:
            self._timeout_seconds = session_timeout  # float or None
        self._sessions: dict[str, float] = {}  # token -> created_at (monotonic or epoch)

    def create_session(
        self,
        *,
        user: bytes | None = None,
        password: bytes | None = None,
    ) -> str | None:
        """
        Authenticate with user/password and create a session if valid.
        Returns a session token or None if credentials are missing or invalid.
        """
        if self.admin_user is None or self.admin_password is None:
            return None
        if user is None or password is None:
            return None
        if not hmac.compare_digest(user, self.admin_user) or not hmac.compare_digest(
            password, self.admin_password
        ):
            return None
        token = secrets.token_urlsafe(32)
        self._sessions[token] = time.monotonic()
        return token

    def validate_session(self, session_token: str) -> bool:
        """
        Return True if the session token exists and (when session_timeout is set) is not expired.
        """
        if not session_token:
            return False
        created = self._sessions.get(session_token)
        if created is None:
            return False
        if self._timeout_seconds is not None:
            if time.monotonic() - created > self._timeout_seconds:
                del self._sessions[session_token]
                return False
        return True