"""RBAC user and token management for v0.3."""

from __future__ import annotations

import hashlib
import logging
import os
import time
from typing import Any

logger = logging.getLogger(__name__)


class Permission:
    """Permission constants for vault operations."""

    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    ADMIN = "admin"
    SYNC = "sync"
    MANAGE = "manage"
    ENCRYPT = "encrypt"


ROLE_PERMISSIONS = {
    "owner": {
        Permission.READ,
        Permission.WRITE,
        Permission.DELETE,
        Permission.ADMIN,
        Permission.SYNC,
        Permission.MANAGE,
        Permission.ENCRYPT,
    },
    "admin": {
        Permission.READ,
        Permission.WRITE,
        Permission.DELETE,
        Permission.ADMIN,
        Permission.SYNC,
    },
    "writer": {Permission.READ, Permission.WRITE, Permission.SYNC},
    "reader": {Permission.READ},
    "mobile": {Permission.READ},
}


class UserManager:
    """Manage user and device tokens for shared vault access."""

    def __init__(self, storage):
        self._storage = storage

    def create_user(self, username: str, role: str = "reader", created_by: str = "system") -> dict[str, str]:
        if role not in ROLE_PERMISSIONS:
            raise ValueError(f"Invalid role: {role}")

        token = hashlib.sha256(os.urandom(32)).hexdigest()
        token_hash = hashlib.sha256(token.encode("utf-8")).hexdigest()
        self._storage.insert_user(
            {
                "username": username,
                "role": role,
                "token_hash": token_hash,
                "created_by": created_by,
                "created_at": int(time.time() * 1000),
                "active": True,
            }
        )

        logger.info("Created user: %s (role=%s)", username, role)
        return {"username": username, "role": role, "token": token}

    def authenticate(self, token: str) -> dict[str, Any] | None:
        token_hash = hashlib.sha256(token.encode("utf-8")).hexdigest()

        user = self._storage.get_user_by_token_hash(token_hash)
        if user and user.get("active"):
            role = str(user.get("role", "reader"))
            return {
                "username": str(user.get("username", "")),
                "role": role,
                "permissions": ROLE_PERMISSIONS.get(role, set()),
                "kind": "user",
            }

        device = self._storage.get_device_token_by_hash(token_hash)
        if device and device.get("active"):
            perms = set(str(p) for p in device.get("permissions", []))
            if not perms:
                perms = {Permission.READ}
            return {
                "username": f"device:{device.get('device_name', 'unknown')}",
                "role": "mobile",
                "permissions": perms,
                "kind": "device",
            }

        return None

    @staticmethod
    def check_permission(user: dict[str, Any], required: str) -> bool:
        perms = user.get("permissions", set())
        if isinstance(perms, list):
            perms = set(str(p) for p in perms)
        if not isinstance(perms, set):
            return False
        return required in perms or Permission.ADMIN in perms

    def create_device_token(self, device_name: str, permissions: set[str] | None = None) -> str:
        token = hashlib.sha256(os.urandom(32)).hexdigest()
        perms = permissions or {Permission.READ}
        self._storage.insert_device_token(
            {
                "device_name": device_name,
                "token_hash": hashlib.sha256(token.encode("utf-8")).hexdigest(),
                "permissions": sorted(list(perms)),
                "created_at": int(time.time() * 1000),
                "active": True,
            }
        )
        return token

    def revoke_user(self, username: str) -> bool:
        return self._storage.deactivate_user(username)

    def list_users(self) -> list[dict[str, Any]]:
        return self._storage.get_all_users()
