"""Tests for write-pipeline code fixes: enable_llm_resolution + strength reinforcement.

Covers:
- enable_llm_resolution=False skips LLM Phase 3 in entity resolution
- Strength reinforcement uses incremental LEAST(1.0, strength + 0.1)
"""

from __future__ import annotations

from unittest.mock import AsyncMock, MagicMock

import pytest
from conftest import FakeEmbeddingProvider

# ===========================================================================
# Tests: enable_llm_resolution
# ===========================================================================


class TestEnableLlmResolution:
    """Tests that enable_llm_resolution=False skips Phase 3 LLM."""

    @pytest.mark.asyncio
    async def test_llm_skipped_when_disabled(self):
        """When enable_llm_resolution=False, _llm_resolve is never called."""
        from arandu.constants import ExtractedEntity
        from arandu.models import MemoryEntity
        from arandu.write.entity_resolution import _resolve_single

        # Create an entity that will produce an ambiguous fuzzy match (0.5-0.85)
        entity = ExtractedEntity(name="Joãozinho", type="person")

        # Mock existing entity with embedding
        existing = MagicMock(spec=MemoryEntity)
        existing.canonical_key = "person:joao"
        existing.display_name = "João"
        existing.entity_type = "person"
        existing.embedding_vec = None  # force difflib fallback

        # LLM provider that should NOT be called
        llm = MagicMock()
        llm.complete = AsyncMock(return_value='{"match_index": 1}')

        session = AsyncMock()
        embeddings = FakeEmbeddingProvider()

        result = await _resolve_single(
            session,
            "user-1",
            entity,
            [existing],
            {},
            llm,
            embeddings=embeddings,
            enable_llm_resolution=False,
        )

        # LLM should NOT have been called
        llm.complete.assert_not_awaited()
        # Result should be a new entity (not matched via LLM)
        assert result.resolution_method in ("new", "nickname", "fuzzy", "exact")

    @pytest.mark.asyncio
    async def test_llm_called_when_enabled(self):
        """When enable_llm_resolution=True (default), Phase 3 LLM runs for ambiguous."""
        from arandu.constants import ExtractedEntity
        from arandu.models import MemoryEntity
        from arandu.write.entity_resolution import _resolve_single

        entity = ExtractedEntity(name="J Silva", type="person")

        existing = MagicMock(spec=MemoryEntity)
        existing.canonical_key = "person:jose_silva"
        existing.display_name = "José Silva"
        existing.entity_type = "person"
        existing.embedding_vec = None

        llm = MagicMock()
        llm.complete = AsyncMock(return_value='{"match_index": 1}')

        session = AsyncMock()
        embeddings = FakeEmbeddingProvider()

        result = await _resolve_single(
            session,
            "user-1",
            entity,
            [existing],
            {},
            llm,
            embeddings=embeddings,
            enable_llm_resolution=True,
        )

        # This test verifies the parameter is accepted and doesn't crash.
        # Whether LLM is actually called depends on fuzzy score — the key
        # point is that enable_llm_resolution=True doesn't block the path.
        assert result is not None

    def test_resolve_entities_accepts_enable_llm_resolution(self):
        """resolve_entities() accepts enable_llm_resolution kwarg."""
        import inspect

        from arandu.write.entity_resolution import resolve_entities

        sig = inspect.signature(resolve_entities)
        assert "enable_llm_resolution" in sig.parameters
        param = sig.parameters["enable_llm_resolution"]
        assert param.default is True


# ===========================================================================
# Tests: Strength reinforcement
# ===========================================================================


class TestStrengthReinforcement:
    """Tests that upsert_relations uses incremental strength."""

    def test_on_conflict_uses_least_not_greatest(self):
        """Verify the SQL expression uses LEAST(1.0, strength + 0.1)."""
        import inspect

        from arandu.write.upsert import upsert_relations

        source = inspect.getsource(upsert_relations)
        assert "LEAST(1.0, memory_entity_relationships.strength + 0.1)" in source
        assert "GREATEST" not in source
