import pytest
from unittest.mock import MagicMock, AsyncMock
from fastapi import FastAPI
from fastapi.testclient import TestClient
from httpx import AsyncClient, ASGITransport
from sqlalchemy.orm import Session
from app.api.dependencies import get_db, ServiceContainer
from app.core.services.rag import RAGService
from app.core.services.document import DocumentService
from app.core.services.tts import TTSService
from app.core.services.stt import STTService
from app.core.services.session import SessionService
from app.api.routes.api import create_api_router

# Change the scope to "function" so the fixture is re-created for each test
@pytest.fixture(scope="function")
def client():
    """
    Pytest fixture to create a TestClient with a fully mocked environment
    for synchronous endpoints, scoped to a single function.
    """
    test_app = FastAPI()

    # Create mocks for all individual services
    mock_rag_service = MagicMock(spec=RAGService)
    mock_document_service = MagicMock(spec=DocumentService)
    mock_tts_service = MagicMock(spec=TTSService)
    mock_stt_service = MagicMock(spec=STTService)
    mock_session_service = MagicMock(spec=SessionService)

    # Create a mock for the ServiceContainer and attach all the individual service mocks
    mock_services = MagicMock(spec=ServiceContainer)
    mock_services.rag_service = mock_rag_service
    mock_services.document_service = mock_document_service
    mock_services.tts_service = mock_tts_service
    mock_services.stt_service = mock_stt_service
    mock_services.session_service = mock_session_service

    # Mock the database session
    mock_db_session = MagicMock(spec=Session)

    # Dependency override for the database session
    def override_get_db():
        yield mock_db_session

    # Create the API router and include it in the test app
    api_router = create_api_router(services=mock_services)
    test_app.dependency_overrides[get_db] = override_get_db
    test_app.include_router(api_router)

    test_client = TestClient(test_app)

    yield test_client, mock_services

@pytest.fixture(scope="function")
async def async_client():
    """
    Pytest fixture to create an AsyncClient for testing async endpoints,
    scoped to a single function.
    """
    test_app = FastAPI()

    # Create mocks for all individual services
    mock_rag_service = MagicMock(spec=RAGService)
    mock_document_service = MagicMock(spec=DocumentService)
    mock_tts_service = MagicMock(spec=TTSService)
    mock_stt_service = MagicMock(spec=STTService)

    # Create a mock for the ServiceContainer and attach all the individual service mocks
    mock_services = MagicMock(spec=ServiceContainer)
    mock_services.rag_service = mock_rag_service
    mock_services.document_service = mock_document_service
    mock_services.tts_service = mock_tts_service
    mock_services.stt_service = mock_stt_service

    # Mock the database session
    mock_db_session = MagicMock(spec=Session)

    # Dependency override for the database session
    def override_get_db():
        yield mock_db_session

    # Create the API router and include it in the test app
    api_router = create_api_router(services=mock_services)
    test_app.dependency_overrides[get_db] = override_get_db
    test_app.include_router(api_router)

    # Use ASGITransport for testing async code
    async with AsyncClient(transport=ASGITransport(app=test_app), base_url="http://test") as client:
        yield client, mock_services