"""Unit tests for review queue."""
from __future__ import annotations

import uuid
from unittest.mock import AsyncMock, MagicMock

import pytest

from libs.review.queue import create_review_item, list_review_items, resolve_review_item


def _make_mock_session() -> AsyncMock:
    session = AsyncMock()
    session.add = MagicMock()
    session.flush = AsyncMock()
    return session


@pytest.mark.unit
class TestCreateReviewItem:
    @pytest.mark.asyncio
    async def test_create_new_review_item(self) -> None:
        """Creating a review item for a new entity adds it to session."""
        session = _make_mock_session()

        # No existing open item
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = None
        session.execute = AsyncMock(return_value=mock_result)

        await create_review_item(
            session=session,
            entity_type="parser_event",
            entity_id="EVT::test::001",
            priority="P1",
            reason_codes=["low_confidence"],
            snapshot_refs={"parse_id": 42},
        )

        session.add.assert_called_once()
        session.flush.assert_called_once()

    @pytest.mark.asyncio
    async def test_deduplicate_open_items(self) -> None:
        """Creating a review item for an already-open entity updates instead of creating."""
        # Simulate existing open item
        existing_item = MagicMock()
        existing_item.status = "open"
        existing_item.priority = "P2"
        existing_item.reason_codes = ["low_confidence"]
        existing_item.suggested_overrides = None

        session = _make_mock_session()
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = existing_item
        session.execute = AsyncMock(return_value=mock_result)

        await create_review_item(
            session=session,
            entity_type="parser_event",
            entity_id="EVT::test::001",
            priority="P0",  # escalate from P2
            reason_codes=["rule_llm_conflict"],
            snapshot_refs={},
        )

        # Should NOT call session.add (update existing instead)
        session.add.assert_not_called()
        # Priority should be escalated
        assert existing_item.priority == "P0"
        # reason_codes merged
        assert "rule_llm_conflict" in existing_item.reason_codes

    @pytest.mark.asyncio
    async def test_resolve_review_item(self) -> None:
        """Resolving an open item updates status, reviewer, resolution fields."""
        existing_item = MagicMock()
        existing_item.status = "open"
        review_id = uuid.uuid4()

        session = _make_mock_session()
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = existing_item
        session.execute = AsyncMock(return_value=mock_result)

        await resolve_review_item(
            session=session,
            review_id=review_id,
            reviewer_id="analyst_01",
            resolution_type="accepted",
            root_cause="data looks correct",
            notes="verified against source",
        )

        assert existing_item.status == "resolved"
        assert existing_item.reviewer_id == "analyst_01"
        assert existing_item.resolution_type == "accepted"

    @pytest.mark.asyncio
    async def test_list_review_items_with_status_filter(self) -> None:
        """list_review_items executes query with status filter and returns results."""
        session = _make_mock_session()
        mock_result = MagicMock()
        mock_scalars = MagicMock()
        mock_scalars.all.return_value = []
        mock_result.scalars.return_value = mock_scalars
        session.execute = AsyncMock(return_value=mock_result)

        items = await list_review_items(session, status="open")

        assert items == []
        session.execute.assert_called_once()
