"""
Trust Levels — Per-user trust classification for the social network.

Four levels:
    OWNER        Everything allowed.
    FRIEND       Chat, file read, file write (prompted), code exec (prompted).
    ROOM_MEMBER  Chat, file read, code exec (prompted, sandboxed only).
    STRANGER     Chat only.

Trust overrides are persisted to ``~/.brynq/trust.json``.
"""

from __future__ import annotations

import json
import logging
import threading
from enum import IntEnum
from pathlib import Path
from typing import Optional

logger = logging.getLogger("brynq.security.trust")

TRUST_FILE = Path.home() / ".brynq" / "trust.json"


class TrustLevel(IntEnum):
    """Trust classification (higher = more trusted)."""

    STRANGER = 0
    ROOM_MEMBER = 1
    FRIEND = 2
    OWNER = 3


# Capabilities granted at each trust level.
# "prompted" means the PermissionManager will ask before allowing.
# "sandboxed" means DockerSandbox is mandatory.
TRUST_CAPABILITIES: dict[TrustLevel, dict[str, dict]] = {
    TrustLevel.OWNER: {
        "chat": {},
        "read_file": {},
        "write_file": {},
        "delete_file": {},
        "run_code": {},
        "access_models": {},
    },
    TrustLevel.FRIEND: {
        "chat": {},
        "read_file": {},
        "write_file": {"prompted": True},
        "run_code": {"prompted": True},
        "access_models": {"prompted": True},
    },
    TrustLevel.ROOM_MEMBER: {
        "chat": {},
        "read_file": {},
        "run_code": {"prompted": True, "sandboxed": True},
    },
    TrustLevel.STRANGER: {
        "chat": {},
    },
}


class TrustManager:
    """Manage per-user trust levels.

    Thread-safe.  Overrides are persisted to disk.
    """

    def __init__(
        self,
        owner_id: str,
        friends: list[str] | None = None,
        path: Path | str | None = None,
    ):
        self._owner_id = owner_id
        self._friends: set[str] = set(friends or [])
        self._path = Path(path) if path else TRUST_FILE
        self._lock = threading.Lock()
        self._overrides: dict[str, int] = {}  # user_id -> TrustLevel value
        self._room_members: set[str] = set()
        self._load()

    # ── public API ────────────────────────────────────────────────────

    def get_trust_level(self, user_id: str) -> TrustLevel:
        """Determine the trust level for *user_id*."""
        if user_id == self._owner_id:
            return TrustLevel.OWNER

        # Explicit override takes priority
        with self._lock:
            override = self._overrides.get(user_id)
        if override is not None:
            return TrustLevel(override)

        # Infer from relationships
        if user_id in self._friends:
            return TrustLevel.FRIEND
        if user_id in self._room_members:
            return TrustLevel.ROOM_MEMBER
        return TrustLevel.STRANGER

    def set_trust_level(self, user_id: str, level: TrustLevel | int) -> None:
        """Set an explicit trust override for *user_id*."""
        level_int = int(level)
        with self._lock:
            self._overrides[user_id] = level_int
            self._save()
        logger.info("Trust for %s set to %s", user_id, TrustLevel(level_int).name)

    def remove_override(self, user_id: str) -> None:
        """Remove the explicit override — user reverts to inferred level."""
        with self._lock:
            self._overrides.pop(user_id, None)
            self._save()

    def add_friend(self, user_id: str) -> None:
        self._friends.add(user_id)

    def remove_friend(self, user_id: str) -> None:
        self._friends.discard(user_id)

    def add_room_member(self, user_id: str) -> None:
        self._room_members.add(user_id)

    def remove_room_member(self, user_id: str) -> None:
        self._room_members.discard(user_id)

    def can_perform(self, user_id: str, action: str) -> dict:
        """Check if *user_id* can perform *action*.

        Returns a dict with keys:
            allowed:   bool — whether the action is in scope at all
            prompted:  bool — whether PermissionManager should ask first
            sandboxed: bool — whether DockerSandbox is required
        """
        level = self.get_trust_level(user_id)
        caps = TRUST_CAPABILITIES.get(level, {})

        if action not in caps:
            return {"allowed": False, "prompted": False, "sandboxed": False}

        props = caps[action]
        return {
            "allowed": True,
            "prompted": props.get("prompted", False),
            "sandboxed": props.get("sandboxed", False),
        }

    def list_overrides(self) -> dict[str, str]:
        """Return all explicit overrides as {user_id: level_name}."""
        with self._lock:
            return {
                uid: TrustLevel(lvl).name
                for uid, lvl in self._overrides.items()
            }

    # ── persistence ───────────────────────────────────────────────────

    def _load(self) -> None:
        if self._path.exists():
            try:
                data = json.loads(self._path.read_text("utf-8"))
                self._overrides = {k: int(v) for k, v in data.get("overrides", {}).items()}
            except (json.JSONDecodeError, OSError) as exc:
                logger.warning("Failed to load trust overrides: %s", exc)
                self._overrides = {}

    def _save(self) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)
        self._path.write_text(
            json.dumps({"overrides": self._overrides}, indent=2),
            encoding="utf-8",
        )
