"""#167: agents could never Edit/Write any file (smoke-10..14).

Root cause: _generate_agent_settings put ``Write(*)``/``Edit(*)`` in the
GLOBAL base_deny. Claude Code evaluates rules deny -> ask -> allow and the
first match wins, so a deny ALWAYS beats a more-specific allow (the glob
syntax has no negation). The global deny therefore unconditionally
shadowed every per-role workspace-scoped Write/Edit allow — every agent,
developers included, got "Edit exists but is not enabled in this context"
and fell back to destructive bash redirection (clobbering real files;
e.g. a 207-line README rewritten to a 3-line stub, which QA correctly
failed).

Second defect: the workspace allow used a SINGLE leading slash
(``Write(/data/...)``). Claude Code resolves a single ``/`` against the
settings.json project root, not the container filesystem root, so even
without the global deny the allow never matched. Absolute container
paths require the ``//`` form.

Fix: drop Write(*)/Edit(*) from base_deny (roles that must not write keep
their OWN Write(*)/Edit(*) deny); emit the workspace allow in the ``//``
absolute form.
"""

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import patch

from roboco.runtime.orchestrator import AgentOrchestrator


def _orch() -> AgentOrchestrator:
    with patch.object(AgentOrchestrator, "__init__", return_value=None):
        return AgentOrchestrator.__new__(AgentOrchestrator)


_WS = "/data/workspaces/roboco-api/backend/be-dev-1"
_CELL = "/data/workspaces/roboco-api/backend"

_WRITER_ROLES = ("developer", "documenter", "product_owner", "head_marketing")
_NON_WRITER_ROLES = ("qa", "cell_pm", "main_pm", "auditor")


def test_generated_settings_base_deny_has_no_global_write_edit() -> None:
    """The settings file a developer is spawned with must NOT globally
    deny Write/Edit (that shadowed the workspace allow → unusable)."""
    orch = _orch()
    path = orch._generate_agent_settings(
        agent_id="be-dev-1",
        role="developer",
        workspace_path=_WS,
        cell_workspace_path=_CELL,
    )
    settings = json.loads(Path(path).read_text())
    deny = settings["permissions"]["deny"]
    allow = settings["permissions"]["allow"]

    assert "Write(*)" not in deny, deny
    assert "Edit(*)" not in deny, deny
    # The security denies that DO rely on deny-always-wins must remain.
    assert "Bash(git:*)" in deny, deny
    assert any(".git/config" in d for d in deny), deny
    # Workspace allow present and in the // absolute form.
    assert f"Write(/{_WS}/**)" in allow, allow
    assert f"Edit(/{_WS}/**)" in allow, allow


def test_writer_roles_use_double_slash_absolute_allow() -> None:
    """Every role that authors files emits Write/Edit allow rules in the
    // absolute-filesystem form (single / silently never matches)."""
    orch = _orch()
    for role in _WRITER_ROLES:
        perms = orch._get_role_permissions(
            role=role, workspace_path=_WS, cell_workspace_path=_CELL
        )
        write_edit = [e for e in perms["allow"] if e.startswith(("Write(", "Edit("))]
        assert write_edit, f"{role} should allow some Write/Edit: {perms}"
        for entry in write_edit:
            inner = entry[entry.index("(") + 1 :]
            assert inner.startswith("//"), (
                f"{role} allow rule must use // absolute form: {entry}"
            )


def test_non_writer_roles_still_deny_write_edit() -> None:
    """Removing the GLOBAL deny must not let QA / PMs / auditor write —
    they carry their own Write(*)/Edit(*) deny in the role config."""
    orch = _orch()
    for role in _NON_WRITER_ROLES:
        perms = orch._get_role_permissions(
            role=role, workspace_path=_WS, cell_workspace_path=_CELL
        )
        assert "Write(*)" in perms["deny"], f"{role}: {perms}"
        assert "Edit(*)" in perms["deny"], f"{role}: {perms}"


def test_non_writer_generated_settings_block_write() -> None:
    """End-to-end: a cell_pm's generated settings still deny Write/Edit
    (their own role deny survives the base_deny change)."""
    orch = _orch()
    path = orch._generate_agent_settings(
        agent_id="be-pm",
        role="cell_pm",
        workspace_path=_WS,
        cell_workspace_path=_CELL,
    )
    deny = json.loads(Path(path).read_text())["permissions"]["deny"]
    assert "Write(*)" in deny, deny
    assert "Edit(*)" in deny, deny
