"""curate_vault content verb — role grant + ContentActions RBAC + flag gating.

Mirrors test_playbook_verbs.py's shape: only the Auditor curates; a
delivery role is refused; the flag off short-circuits before any write.
"""

from __future__ import annotations

from unittest.mock import AsyncMock, MagicMock, patch
from uuid import uuid4

import pytest
from roboco.config import settings
from roboco.services.gateway.content_actions import ContentActions, ContentActionsDeps
from roboco.services.gateway.role_config import get_role_config


def _actions(role: str) -> ContentActions:
    task = MagicMock()
    agent = MagicMock()
    agent.role = role
    task.agent_for = AsyncMock(return_value=agent)
    task.session = AsyncMock()
    deps = ContentActionsDeps(
        task=task,
        git=MagicMock(),
        a2a=MagicMock(),
        journal=MagicMock(),
        workspace=MagicMock(),
        notifications=MagicMock(),
    )
    return ContentActions(deps)


def test_auditor_can_curate_vault() -> None:
    assert "curate_vault" in get_role_config("auditor").do_tools


def test_developer_cannot_curate_vault() -> None:
    assert "curate_vault" not in get_role_config("developer").do_tools


@pytest.mark.asyncio
async def test_curate_vault_forbidden_for_developer(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(settings, "obsidian_vault_enabled", True)
    env = await _actions("developer").curate_vault(
        agent_id=uuid4(), task_id=uuid4(), narrative="did stuff"
    )
    assert env.error == "not_authorized"


@pytest.mark.asyncio
async def test_curate_vault_disabled_when_flag_off(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(settings, "obsidian_vault_enabled", False)
    env = await _actions("auditor").curate_vault(
        agent_id=uuid4(), task_id=uuid4(), narrative="did stuff"
    )
    assert env.error == "invalid_state"


@pytest.mark.asyncio
async def test_curate_vault_not_found(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(settings, "obsidian_vault_enabled", True)
    actions = _actions("auditor")
    actions.task.get = AsyncMock(return_value=None)
    env = await actions.curate_vault(
        agent_id=uuid4(), task_id=uuid4(), narrative="did stuff"
    )
    assert env.error == "not_found"


@pytest.mark.asyncio
async def test_curate_vault_writes_narrative_for_auditor(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(settings, "obsidian_vault_enabled", True)
    actions = _actions("auditor")
    task_id = uuid4()
    task = MagicMock()
    actions.task.get = AsyncMock(return_value=task)
    writer = MagicMock()
    data = MagicMock()
    with (
        patch(
            "roboco.services.vault_assembly.assemble_task_note_data",
            AsyncMock(return_value=data),
        ) as assemble,
        patch("roboco.services.vault_writer.get_vault_writer", return_value=writer),
        patch("roboco.services.project.get_project_service"),
    ):
        env = await actions.curate_vault(
            agent_id=uuid4(), task_id=task_id, narrative="Shipped after one rework."
        )
    assert env.error is None
    assert env.status == "vault_curated"
    assemble.assert_awaited_once()
    assert assemble.await_args is not None
    assert assemble.await_args.kwargs["narrative"] == "Shipped after one rework."
    writer.write_task.assert_called_once_with(data)


@pytest.mark.asyncio
async def test_curate_vault_write_failure_returns_invalid_state(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(settings, "obsidian_vault_enabled", True)
    actions = _actions("auditor")
    actions.task.get = AsyncMock(return_value=MagicMock())
    with (
        patch(
            "roboco.services.vault_assembly.assemble_task_note_data",
            AsyncMock(side_effect=OSError("disk full")),
        ),
        patch("roboco.services.project.get_project_service"),
    ):
        env = await actions.curate_vault(
            agent_id=uuid4(), task_id=uuid4(), narrative="x"
        )
    assert env.error == "invalid_state"
