"""Tests for the public chat endpoint contracts."""

import os
import unittest
from unittest.mock import AsyncMock, MagicMock

from fastapi import HTTPException
from pydantic import ValidationError

os.environ.setdefault("NEON_DATABASE_URL", "postgresql://user:pass@localhost:5432/testdb")
os.environ.setdefault("BETTER_AUTH_URL", "http://localhost:3000")
os.environ.setdefault("INTERNAL_EMAIL_SHARED_SECRET", "test-secret")
os.environ.setdefault("REDIS_URL", "redis://localhost:6379/0")

from app.routers.chat import (  # noqa: E402
    PublicChatRequest,
    _resolve_restaurant_by_slug,
    limiter,
    public_router,
)


class TestPublicChatRequestSchema(unittest.TestCase):
    """Validate PublicChatRequest pydantic schema."""

    def test_valid_request_with_all_fields(self) -> None:
        req = PublicChatRequest(
            restaurant_slug="bobs-burgers",
            message="Hello!",
            conversation_id="conv-123",
            agent_type="guest",
        )
        self.assertEqual(req.restaurant_slug, "bobs-burgers")
        self.assertEqual(req.message, "Hello!")
        self.assertEqual(req.conversation_id, "conv-123")
        self.assertEqual(req.agent_type, "guest")

    def test_minimal_request_only_required_fields(self) -> None:
        req = PublicChatRequest(restaurant_slug="taco-bell", message="Menu?")
        self.assertEqual(req.restaurant_slug, "taco-bell")
        self.assertEqual(req.message, "Menu?")
        self.assertIsNone(req.conversation_id)
        self.assertIsNone(req.agent_type)

    def test_missing_slug_raises_validation_error(self) -> None:
        with self.assertRaises(ValidationError):
            PublicChatRequest(message="Hi")  # type: ignore[call-arg]

    def test_missing_message_raises_validation_error(self) -> None:
        with self.assertRaises(ValidationError):
            PublicChatRequest(restaurant_slug="slug")  # type: ignore[call-arg]


class TestPublicChatRouterSetup(unittest.TestCase):
    """Validate router and limiter configuration."""

    def test_public_router_prefix(self) -> None:
        self.assertEqual(public_router.prefix, "/public/chat")

    def test_public_router_has_stream_route(self) -> None:
        self.assertTrue(
            any(getattr(route, "path", "").endswith("/stream") for route in public_router.routes)
        )

    def test_limiter_is_configured(self) -> None:
        self.assertIsNotNone(limiter)
        self.assertEqual(getattr(limiter._key_func, "__name__", ""), "get_remote_address")


class TestSlugResolution(unittest.IsolatedAsyncioTestCase):
    """Validate _resolve_restaurant_by_slug behaviour."""

    async def test_resolve_unknown_slug_raises_404(self) -> None:
        mock_session = AsyncMock()
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = None
        mock_session.execute.return_value = mock_result

        with self.assertRaises(HTTPException) as ctx:
            await _resolve_restaurant_by_slug("no-such-place", mock_session)

        self.assertEqual(ctx.exception.status_code, 404)

    async def test_resolve_known_slug_returns_restaurant(self) -> None:
        mock_restaurant = MagicMock()
        mock_restaurant.slug = "bobs-burgers"

        mock_session = AsyncMock()
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = mock_restaurant
        mock_session.execute.return_value = mock_result

        result = await _resolve_restaurant_by_slug("bobs-burgers", mock_session)
        self.assertIs(result, mock_restaurant)
