"""Role-based approval and manual override tokens."""

from __future__ import annotations

import secrets
import time
from dataclasses import dataclass

from interceptor.exceptions import OverrideTokenError
from interceptor.types import RiskLevel

# Roles that can approve HIGH-risk actions without an override token.
ADMIN_ROLES: set[str] = {"admin", "system"}


class RoleApproval:
    """Check whether a user role is authorized for a given risk level."""

    @staticmethod
    def is_authorized(user_role: str, risk_level: RiskLevel) -> bool:
        """Return ``True`` if *user_role* can execute an action at *risk_level*."""
        if risk_level == RiskLevel.HIGH:
            return user_role.lower() in ADMIN_ROLES
        return True


@dataclass
class _Token:
    value: str
    expires_at: float
    consumed: bool = False


class OverrideToken:
    """Generate, validate, and consume single-use override tokens."""

    def __init__(self, ttl_seconds: float = 300.0) -> None:
        self._ttl = ttl_seconds
        self._tokens: dict[str, _Token] = {}

    def generate(self) -> str:
        """Create a new token valid for ``ttl_seconds``."""
        value = secrets.token_urlsafe(32)
        self._tokens[value] = _Token(
            value=value,
            expires_at=time.time() + self._ttl,
        )
        return value

    def validate_and_consume(self, token: str) -> bool:
        """Consume *token* if valid.  Raises on failure."""
        entry = self._tokens.get(token)
        if entry is None:
            raise OverrideTokenError("Unknown override token.")
        if entry.consumed:
            raise OverrideTokenError("Override token already consumed.")
        if time.time() > entry.expires_at:
            raise OverrideTokenError("Override token has expired.")
        entry.consumed = True
        return True
