"""Block author mutations from reviewer-bound MCP namespaces (#209).

Every mutation must prove that the active profile role, inferred MCP
namespace, and declared task role align. Reviewer sessions cannot silently
perform author-side work (especially PR creation).
"""

from __future__ import annotations

import gitea_config
import role_session_router


def infer_mcp_namespace(profile_name: str | None) -> str:
    """Map a runtime profile name to its MCP namespace label."""
    lower = (profile_name or "").strip().lower()
    if "reviewer" in lower and "author" not in lower:
        return "gitea-reviewer"
    if "author" in lower:
        return "gitea-author"
    return profile_name or "gitea-default"


def derive_role_kind(allowed, forbidden=()) -> str:
    """Classify the active profile the same way as ``mcp_server._role_kind``."""

    def can(op):
        return gitea_config.check_operation(op, allowed, forbidden)[0]

    review = can("gitea.pr.approve") or can("gitea.pr.merge")
    author = can("gitea.pr.create") or can("gitea.branch.push")
    if review and author:
        return "mixed"
    if review:
        return "reviewer"
    if author:
        return "author"
    return "limited"


def check_author_mutation_namespace(
    mutation_task: str,
    profile: dict,
) -> tuple[bool, list[str]]:
    """Return (allowed, reasons). Fail closed on reviewer/author mismatch."""
    required_role = role_session_router.required_role_for_task(mutation_task)
    if required_role != "author":
        return True, []

    allowed = profile.get("allowed_operations") or []
    forbidden = profile.get("forbidden_operations") or []
    active_role = derive_role_kind(allowed, forbidden)
    profile_name = profile.get("profile_name") or ""
    namespace = infer_mcp_namespace(profile_name)

    if mutation_task == "create_pr":
        if active_role == "reviewer" or namespace == "gitea-reviewer":
            return False, [
                "author mutation 'create_pr' blocked in reviewer MCP namespace "
                f"({namespace}); launch gitea-author",
            ]

    if active_role == "reviewer" or namespace == "gitea-reviewer":
        if mutation_task == "create_issue":
            ok, _ = gitea_config.check_operation(
                "gitea.issue.create", allowed, forbidden)
            if ok:
                return True, []
        return False, [
            f"author mutation '{mutation_task}' blocked: active session is "
            f"reviewer-bound ({profile_name} / {namespace})",
        ]

    return True, []


def mutation_audit_context(mutation_task: str, profile: dict, *,
                           remote=None, repository=None) -> dict:
    """Structured mutation metadata for audit records (#209)."""
    allowed = profile.get("allowed_operations") or []
    forbidden = profile.get("forbidden_operations") or []
    return {
        "mcp_namespace": infer_mcp_namespace(profile.get("profile_name")),
        "profile_name": profile.get("profile_name"),
        "task_role": role_session_router.required_role_for_task(mutation_task),
        "operation": mutation_task,
        "remote": remote,
        "repository": repository,
    }