"""Benchmarks for the permission check enforcement baseline.

Measures the overhead of permission checks in both local mode
(fast-path) and server mode with varying numbers of role bindings.
"""

from __future__ import annotations

import os
from typing import ClassVar

from cleveragents.application.services.permission_service import (
    PermissionService,
)
from cleveragents.domain.models.core.permission import (
    ROLE_PERMISSIONS,
    PermissionAction,
    PermissionRole,
    PermissionScope,
    RoleBinding,
)

_SERVER_MODE_ENV = "CLEVERAGENTS_SERVER_MODE"


def _make_bindings(n: int) -> list[RoleBinding]:
    """Create *n* role bindings for distinct principals."""
    return [
        RoleBinding(
            principal=f"user-{i}",
            role=PermissionRole.EDITOR,
            scope=PermissionScope.PROJECT,
            scope_id="proj-bench",
        )
        for i in range(n)
    ]


class TimePermissionCheckLocal:
    """Benchmark permission checks in local mode (fast-path)."""

    def setup(self) -> None:
        os.environ.pop(_SERVER_MODE_ENV, None)
        self.svc = PermissionService()

    def time_local_check(self) -> None:
        """Single local-mode permission check."""
        self.svc.check_permission(
            principal="alice",
            action=PermissionAction.WRITE,
            scope=PermissionScope.PROJECT,
            scope_id="proj-1",
        )

    def time_local_check_all_actions(self) -> None:
        """Check every action in local mode."""
        for action in PermissionAction:
            self.svc.check_permission(
                principal="alice",
                action=action,
                scope=PermissionScope.PROJECT,
                scope_id="proj-1",
            )


class TimePermissionCheckServer:
    """Benchmark permission checks in server mode."""

    params: ClassVar[list[int]] = [0, 10, 100]
    param_names: ClassVar[list[str]] = ["num_bindings"]

    def setup(self, num_bindings: int) -> None:
        os.environ[_SERVER_MODE_ENV] = "true"
        bindings = _make_bindings(num_bindings)
        self.svc = PermissionService(bindings=bindings)

    def teardown(self, num_bindings: int) -> None:
        os.environ.pop(_SERVER_MODE_ENV, None)

    def time_server_check_denied(self, num_bindings: int) -> None:
        """Permission check that results in denial (no matching binding)."""
        self.svc.check_permission(
            principal="nonexistent",
            action=PermissionAction.WRITE,
            scope=PermissionScope.PROJECT,
            scope_id="proj-bench",
        )

    def time_server_check_allowed(self, num_bindings: int) -> None:
        """Permission check that matches the last binding.

        When *num_bindings* is 0 no binding can match, so a denied
        check is performed instead to avoid an empty benchmark body.
        """
        principal = f"user-{num_bindings - 1}" if num_bindings > 0 else "nonexistent"
        self.svc.check_permission(
            principal=principal,
            action=PermissionAction.READ,
            scope=PermissionScope.PROJECT,
            scope_id="proj-bench",
        )


class TimeRolePermissionsLookup:
    """Benchmark ROLE_PERMISSIONS constant lookups."""

    def time_lookup_all_roles(self) -> None:
        """Look up allowed actions for every role."""
        for role in PermissionRole:
            _ = ROLE_PERMISSIONS[role]

    def time_check_action_in_role(self) -> None:
        """Check membership of an action in each role's permission set."""
        for role in PermissionRole:
            _ = PermissionAction.READ in ROLE_PERMISSIONS[role]
