"""Tests for Router <-> BackendDispatcher integration (privacy enforcement)."""

from __future__ import annotations

import pytest

from llmhosts.config import ConnectionPoolConfig
from llmhosts.proxy.dispatcher import BackendDispatcher, BackendEntry
from llmhosts.proxy.models import UnifiedMessage, UnifiedRequest
from llmhosts.router.engine import Router
from llmhosts.router.models import BackendInfo

# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


@pytest.fixture
def local_backend_entry() -> BackendEntry:
    return BackendEntry(
        name="local-core",
        base_url="http://127.0.0.1:11434",
        backend_type="llmhosts-core",
        models=["llama3.2"],
        priority=0,
        healthy=True,
    )


@pytest.fixture
def router_with_local_backend() -> Router:
    router = Router()
    router.register_backend(
        BackendInfo(
            backend_type="llmhosts-core",
            url="http://127.0.0.1:11434",
            models=["llama3.2"],
            is_local=True,
            is_healthy=True,
        )
    )
    return router


@pytest.fixture
def dispatcher_with_router(router_with_local_backend: Router, local_backend_entry: BackendEntry) -> BackendDispatcher:
    """BackendDispatcher with a Router attached and one local backend registered."""
    dispatcher = BackendDispatcher.__new__(BackendDispatcher)
    dispatcher._backends = [local_backend_entry]
    dispatcher._pool_registry = {}
    dispatcher._pool_config = ConnectionPoolConfig()
    dispatcher._backend_manager = None
    dispatcher._core_engine = None
    dispatcher._router = None  # will be set by attach_router
    dispatcher.attach_router(router_with_local_backend)
    return dispatcher


@pytest.fixture
def sensitive_request() -> UnifiedRequest:
    return UnifiedRequest(
        model="llama3.2",
        messages=[UnifiedMessage(role="user", content="My SSN is 123-45-6789")],
    )


@pytest.fixture
def public_request() -> UnifiedRequest:
    return UnifiedRequest(
        model="llama3.2",
        messages=[UnifiedMessage(role="user", content="What is the capital of France?")],
    )


# ---------------------------------------------------------------------------
# Tests: Router routing decisions
# ---------------------------------------------------------------------------


async def test_router_detects_sensitive_pii(
    router_with_local_backend: Router, sensitive_request: UnifiedRequest
) -> None:
    """Router must classify an SSN as SENSITIVE tier."""
    decision = await router_with_local_backend.route(sensitive_request)
    assert decision.privacy_tier == "sensitive"
    assert "ssn" in decision.privacy_pii_types


async def test_router_allows_public_cloud_routing(
    router_with_local_backend: Router, public_request: UnifiedRequest
) -> None:
    """Public requests should not be flagged as sensitive."""
    decision = await router_with_local_backend.route(public_request)
    assert decision.privacy_tier == "public"


# ---------------------------------------------------------------------------
# Tests: BackendDispatcher privacy-aware selection
# ---------------------------------------------------------------------------


async def test_sensitive_request_routed_to_local_backend(
    dispatcher_with_router: BackendDispatcher,
    sensitive_request: UnifiedRequest,
    local_backend_entry: BackendEntry,
) -> None:
    """SENSITIVE PII must be routed to a local backend."""
    entry = await dispatcher_with_router._select_backend_with_privacy(sensitive_request)
    assert entry.backend_type == "llmhosts-core"
    assert entry.base_url == local_backend_entry.base_url


async def test_public_request_uses_normal_selection(
    dispatcher_with_router: BackendDispatcher,
    public_request: UnifiedRequest,
) -> None:
    """Public requests should fall through to normal _select_backend logic."""
    entry = await dispatcher_with_router._select_backend_with_privacy(public_request)
    # Should still return a valid backend (the local one, since no cloud in test)
    assert entry.backend_type == "llmhosts-core"


async def test_no_router_falls_back_to_rule_based(
    local_backend_entry: BackendEntry, sensitive_request: UnifiedRequest
) -> None:
    """Without a Router attached, dispatcher falls back to normal selection."""
    dispatcher = BackendDispatcher.__new__(BackendDispatcher)
    dispatcher._backends = [local_backend_entry]
    dispatcher._pool_registry = {}
    dispatcher._pool_config = ConnectionPoolConfig()
    dispatcher._backend_manager = None
    dispatcher._core_engine = None
    dispatcher._router = None

    entry = await dispatcher._select_backend_with_privacy(sensitive_request)
    assert entry.backend_type == "llmhosts-core"


async def test_attach_router_sets_attribute(
    router_with_local_backend: Router,
    local_backend_entry: BackendEntry,
) -> None:
    """attach_router must set _router on the dispatcher."""
    dispatcher = BackendDispatcher.__new__(BackendDispatcher)
    dispatcher._backends = [local_backend_entry]
    dispatcher._pool_registry = {}
    dispatcher._pool_config = ConnectionPoolConfig()
    dispatcher._backend_manager = None
    dispatcher._core_engine = None
    dispatcher._router = None

    assert dispatcher._router is None
    dispatcher.attach_router(router_with_local_backend)
    assert dispatcher._router is router_with_local_backend
