"""Tests for per-role spawn manifest construction."""

from __future__ import annotations

import json
from pathlib import Path
from uuid import uuid4

import pytest
from roboco.runtime.spawn_manifest import SpawnInputs, build_for_role, write_manifest


class TestBuildForRole:
    def test_developer_manifest(self) -> None:
        m = build_for_role(
            SpawnInputs(
                agent_id=uuid4(),
                role="developer",
                team="backend",
                workspace_path=Path("/data/workspaces/roboco/backend/be-dev-1"),
                agent_model="minimax-m3:cloud",
            )
        )
        assert "i_am_done" in m.flow_tools
        assert "commit" in m.do_tools
        # Issue #8: the developer manifest must carry `evidence` so the
        # do-server registers mcp__roboco-do__evidence inside the container.
        assert "evidence" in m.do_tools
        assert "Edit" in m.write_tools
        assert m.subagent_allowed is False
        assert m.subagent_model is None  # devs don't dispatch
        assert m.bash_allowed is True
        assert "ROBOCO_SDK_URL" in m.env or "ROBOCO_PUBLIC_BASE_URL" in m.env

    def test_main_pm_manifest_subagent_uses_parent_model(self) -> None:
        m = build_for_role(
            SpawnInputs(
                agent_id=uuid4(),
                role="main_pm",
                team="board",
                workspace_path=Path("/data/workspaces/roboco/board/main-pm"),
                agent_model="minimax-m3:cloud",
            )
        )
        assert m.subagent_allowed is True
        assert m.subagent_model == "minimax-m3:cloud"

    def test_qa_manifest_no_write(self) -> None:
        m = build_for_role(
            SpawnInputs(
                agent_id=uuid4(),
                role="qa",
                team="backend",
                workspace_path=Path("/data/workspaces/roboco/backend/be-qa"),
                agent_model="minimax-m3:cloud",
            )
        )
        assert m.write_tools == []

    def test_unknown_role_raises(self) -> None:
        with pytest.raises(KeyError):
            build_for_role(
                SpawnInputs(
                    agent_id=uuid4(),
                    role="unknown",
                    team="x",
                    workspace_path=Path("/tmp/x"),
                    agent_model="x",
                )
            )

    @pytest.mark.parametrize("role", ["product_owner", "head_marketing"])
    def test_board_roles_carry_read_messages(self, role: str) -> None:
        """Board roles must keep read_messages so they can clear unread A2A and
        i_am_idle (clean shutdown). A board agent spawned from a manifest that
        omits it gets soft-blocked on i_am_idle forever — guard against the grant
        silently dropping from _BOARD_DO.
        """
        m = build_for_role(
            SpawnInputs(
                agent_id=uuid4(),
                role=role,
                team="board",
                workspace_path=Path("/tmp/x"),
                agent_model="claude-opus-4-6",
            )
        )
        assert "read_messages" in m.do_tools
        # The full A2A/notification-receiver set must be present together.
        for tool in ("notify_list", "notify_get", "notify_ack"):
            assert tool in m.do_tools


class TestWriteManifest:
    def test_writes_json(self, tmp_path: Path) -> None:
        m = build_for_role(
            SpawnInputs(
                agent_id=uuid4(),
                role="developer",
                team="backend",
                workspace_path=tmp_path,
                agent_model="claude-opus-4-7",
            )
        )
        manifest_path = tmp_path / "tool-manifest.json"
        write_manifest(m, manifest_path)
        data = json.loads(manifest_path.read_text())
        assert data["role"] == "developer"
        assert "i_am_done" in data["flow_tools"]
        assert data["bash_allowed"] is True
