"""Chat attribution must follow each prompt author, not the viewer or session owner."""

from datetime import UTC, datetime
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch
from uuid import uuid4

import pytest
from src.domain.auth.facades import UserFacadeImpl
from src.domain.builder.service import WorkspaceHydrateService
from src.domain.instructions.repository import PromptRepository


@pytest.mark.asyncio
async def test_author_labels_are_batched_and_use_profile_fallbacks():
    users = [
        SimpleNamespace(
            id=uuid4(),
            display_name=" Alice ",
            first_name=None,
            last_name=None,
            email="a@example.com",
        ),
        SimpleNamespace(
            id=uuid4(),
            display_name=" ",
            first_name=" Bob ",
            last_name=" Smith ",
            email="b@example.com",
        ),
        SimpleNamespace(
            id=uuid4(),
            display_name=None,
            first_name=None,
            last_name=None,
            email="charlie@example.com",
        ),
    ]
    repo = SimpleNamespace(list_by_ids=AsyncMock(return_value=users))
    labels = await UserFacadeImpl(repo).get_user_labels([u.id for u in users] + [users[0].id])
    assert list(labels.values()) == ["Alice", "Bob Smith", "charlie"]
    repo.list_by_ids.assert_awaited_once_with([u.id for u in users])


@pytest.mark.asyncio
async def test_prompt_labels_use_each_prompt_user_id_and_leave_unknown_unattributed():
    alice, bob = uuid4(), uuid4()
    prompts = [SimpleNamespace(id=uuid4(), user_id=uid) for uid in [alice, bob, None, uuid4()]]
    with patch.object(
        UserFacadeImpl, "get_user_labels", AsyncMock(return_value={alice: "Alice", bob: "Bob"})
    ) as lookup:
        labels = await PromptRepository(MagicMock()).get_sender_labels(prompts)
    assert labels == {prompts[0].id: "Alice", prompts[1].id: "Bob"}
    lookup.assert_awaited_once_with([p.user_id for p in prompts if p.user_id])


@pytest.mark.asyncio
@pytest.mark.parametrize("unified", [False, True])
async def test_hydrate_preserves_distinct_authors_for_legacy_and_unified_history(unified):
    prompts = [
        SimpleNamespace(
            id=uuid4(),
            content="Build it",
            context=None,
            response=None,
            created_at=datetime.now(UTC),
        )
        for _ in range(3)
    ]
    labels = {prompts[0].id: "Alice", prompts[1].id: "Bob"}
    run_id = uuid4()
    rows = []
    if unified:
        for role in ["user", "assistant"]:
            rows.append(
                SimpleNamespace(
                    id=uuid4(),
                    content="Message",
                    created_at=prompts[0].created_at,
                    run_id=run_id,
                    role=role,
                    message_type="message",
                    payload=None,
                    prompt_id=prompts[0].id,
                )
            )
    service = WorkspaceHydrateService(
        **{
            name: MagicMock()
            for name in [
                "project_repo",
                "revision_repo",
                "codegen_repo",
                "prompt_session_repo",
                "prompt_repo",
                "run_chat_repo",
                "preview_repo",
                "manifest_repo",
                "deploy_repo",
                "domain_repo",
                "timeline_repo",
                "changed_file_repo",
            ]
        }
    )
    service._prompt_repo.list_for_session = AsyncMock(return_value=prompts)
    service._prompt_repo.get_sender_labels = AsyncMock(return_value=labels)
    service._codegen_repo.list_for_project = AsyncMock(return_value=[])
    service._run_chat_repo.list_for_session = AsyncMock(return_value=rows)
    result = await service._build_session_prompt(uuid4(), uuid4())
    user_rows = [row for row in result.current_prompt_slice if row.role != "assistant"]
    assert [row.sender_label for row in user_rows] == ["Alice", "Bob", None]
    assert all(
        row.sender_label is None for row in result.current_prompt_slice if row.role == "assistant"
    )
