"""Every gateway commit message gets [task-id-short] prefix.

ContentActions.commit promises in the dev prompt that `[task-id]` is
auto-prefixed onto every commit. The gateway strips any user-supplied
prefix via `_TASK_ID_PREFIX_RE` but, before this guard, never re-added
the canonical one. These tests pin the contract.
"""

from __future__ import annotations

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

import pytest
from roboco.services.gateway.content_actions import ContentActions, ContentActionsDeps


def _make_deps(**overrides: AsyncMock) -> ContentActionsDeps:
    """Build a ContentActionsDeps for tests; mirrors test_content_actions."""
    if "task" in overrides:
        task = overrides["task"]
    else:
        task = AsyncMock()
        task.get_active_task_for_agent.return_value = None

    # commit() now checks caller role; default to developer.

    task.agent_for.return_value = MagicMock(role="developer")

    if "git" in overrides:
        git = overrides["git"]
    else:
        git = AsyncMock()
        git.commit.return_value = {"sha": "abc12345"}
        git.diff.return_value = ""

    messaging = overrides.get("messaging", AsyncMock())
    a2a = overrides.get("a2a", AsyncMock())
    journal = overrides.get("journal", AsyncMock())
    workspace = overrides.get("workspace", AsyncMock())
    notifications = overrides.get("notifications", AsyncMock())
    return ContentActionsDeps(
        task=task,
        git=git,
        messaging=messaging,
        a2a=a2a,
        journal=journal,
        workspace=workspace,
        notifications=notifications,
    )


@pytest.mark.asyncio
async def test_commit_prefixes_with_task_id_short() -> None:
    """Plain message gets `[task-id-short] ` prepended."""
    aid = uuid4()
    tid = uuid4()
    expected_prefix = f"[{str(tid)[:8]}]"

    t = MagicMock(
        id=tid,
        assigned_to=aid,
        active_claimant_id=aid,
        plan="x",
        status="in_progress",
        branch_name="feature/backend/abcd1234",
    )
    task_svc = AsyncMock()
    task_svc.get_active_task_for_agent.return_value = t
    git_svc = AsyncMock()
    git_svc.commit.return_value = {"sha": "deadbeef"}

    deps = _make_deps(task=task_svc, git=git_svc)
    actions = ContentActions(deps)

    await actions.commit(
        agent_id=aid,
        message="feat(api): add login endpoint for session bootstrap",
    )

    git_svc.commit.assert_awaited()
    # git.commit takes keyword-only args (branch_name, message, task_id, files)
    msg = git_svc.commit.await_args.kwargs["message"]
    assert msg.startswith(expected_prefix), (
        f"expected {expected_prefix} prefix; got {msg!r}"
    )


@pytest.mark.asyncio
async def test_commit_strips_then_re_adds_prefix() -> None:
    """If the agent supplied a wrong prefix, strip it and add the canonical one."""
    aid = uuid4()
    tid = uuid4()
    expected_prefix = f"[{str(tid)[:8]}]"

    t = MagicMock(
        id=tid,
        assigned_to=aid,
        active_claimant_id=aid,
        plan="x",
        status="in_progress",
        branch_name="feature/backend/abcd1234",
    )
    task_svc = AsyncMock()
    task_svc.get_active_task_for_agent.return_value = t
    git_svc = AsyncMock()
    git_svc.commit.return_value = {"sha": "deadbeef"}

    deps = _make_deps(task=task_svc, git=git_svc)
    actions = ContentActions(deps)

    await actions.commit(
        agent_id=aid,
        message="[wrong-id] feat(api): add login endpoint for session bootstrap",
    )

    msg = git_svc.commit.await_args.kwargs["message"]
    assert msg.startswith(expected_prefix)
    assert "[wrong-id]" not in msg


@pytest.mark.asyncio
async def test_commit_prefix_collapses_multiple_spaces() -> None:
    """`[old]   foo` should become `[new] foo`, not `[new]   foo`."""
    aid = uuid4()
    tid = uuid4()
    expected_prefix = f"[{str(tid)[:8]}]"

    t = MagicMock(
        id=tid,
        assigned_to=aid,
        active_claimant_id=aid,
        plan="x",
        status="in_progress",
        branch_name="feature/backend/abcd1234",
    )
    task_svc = AsyncMock()
    task_svc.get_active_task_for_agent.return_value = t
    git_svc = AsyncMock()
    git_svc.commit.return_value = {"sha": "deadbeef"}

    deps = _make_deps(task=task_svc, git=git_svc)
    actions = ContentActions(deps)

    await actions.commit(
        agent_id=aid,
        message="[old]   feat(api): add login endpoint for session bootstrap",
    )

    msg = git_svc.commit.await_args.kwargs["message"]
    # Exactly one space after the prefix bracket
    assert msg.startswith(f"{expected_prefix} feat(api):"), (
        f"expected single-space prefix; got {msg!r}"
    )
