import sys
from unittest.mock import Mock

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

sys.modules.setdefault('psutil', Mock())

import app.models  # noqa: F401
from app.database import Base, get_db
from app.models.brain import BrainCandidate, BrainEvent, BrainMemory, BrainTag
from app.models.user import User
from app.routers.auth import get_current_user
from app.routers.brain import router as brain_router
from app.services.auth_service import get_password_hash


@pytest.fixture
async def brain_router_env(tmp_path):
    db_path = tmp_path / 'test_brain_router.db'
    engine = create_async_engine(f"sqlite+aiosqlite:///{db_path}", future=True)
    session_factory = async_sessionmaker(engine, expire_on_commit=False)

    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    async with session_factory() as session:
        user = User(
            email='brain@example.com',
            hashed_password=get_password_hash('secret123'),
            full_name='Brain Tester',
        )
        session.add(user)
        await session.flush()

        session.add_all([
            BrainMemory(
                user_id=user.id,
                memory_type='project_fact',
                title='Current project direction',
                content='Jarvis knowledge brain should learn from all major product surfaces.',
                importance=8,
                confidence=0.92,
                status='active',
            ),
            BrainMemory(
                user_id=user.id,
                memory_type='preference',
                title='User prefers brain-first UX',
                content='The knowledge brain should be broader than the graph page.',
                importance=7,
                confidence=0.88,
                status='active',
            ),
            BrainTag(
                user_id=user.id,
                name='knowledge-brain',
                category='topic',
                priority='important',
                score=9.5,
            ),
            BrainTag(
                user_id=user.id,
                name='graph',
                category='topic',
                priority='secondary',
                score=4.0,
            ),
            BrainEvent(
                user_id=user.id,
                source_type='conversation',
                source_id='conv-1',
                event_type='created',
                title='Conversation created',
                content_summary='User described the desired knowledge brain behavior.',
                status='pending',
            ),
            BrainEvent(
                user_id=user.id,
                source_type='document',
                source_id='doc-1',
                event_type='indexed',
                title='Document indexed',
                content_summary='A strategic document was indexed into the system.',
                status='processed',
            ),
            BrainCandidate(
                user_id=user.id,
                candidate_type='project_fact',
                title='Brain spans all product surfaces',
                summary='The knowledge brain should learn from conversation, docs, tasks, todos, and forum.',
                importance_score=9.2,
                confidence_score=0.95,
                status='new',
            ),
        ])
        await session.commit()
        await session.refresh(user)

    async def override_get_db():
        async with session_factory() as session:
            yield session

    async def override_get_current_user():
        return user

    test_app = FastAPI()
    test_app.include_router(brain_router)
    test_app.dependency_overrides[get_db] = override_get_db
    test_app.dependency_overrides[get_current_user] = override_get_current_user

    try:
        yield test_app
    finally:
        await engine.dispose()


@pytest.mark.asyncio
async def test_brain_overview_returns_memory_and_tag_summary(brain_router_env):
    transport = ASGITransport(app=brain_router_env)

    async with AsyncClient(transport=transport, base_url='http://testserver') as client:
        response = await client.get('/api/brain/overview')

    assert response.status_code == 200
    payload = response.json()
    assert payload['active_memory_count'] == 2
    assert payload['important_tag_count'] == 1
    assert payload['secondary_tag_count'] == 1
    assert payload['recent_memory_titles'] == [
        'Current project direction',
        'User prefers brain-first UX',
    ]


@pytest.mark.asyncio
async def test_list_brain_memories_returns_active_memories_sorted_by_importance(brain_router_env):
    transport = ASGITransport(app=brain_router_env)

    async with AsyncClient(transport=transport, base_url='http://testserver') as client:
        response = await client.get('/api/brain/memories')

    assert response.status_code == 200
    payload = response.json()
    assert [item['title'] for item in payload] == [
        'Current project direction',
        'User prefers brain-first UX',
    ]
    assert all(item['status'] == 'active' for item in payload)


@pytest.mark.asyncio
async def test_list_brain_tags_groups_important_and_secondary_tags(brain_router_env):
    transport = ASGITransport(app=brain_router_env)

    async with AsyncClient(transport=transport, base_url='http://testserver') as client:
        response = await client.get('/api/brain/tags')

    assert response.status_code == 200
    payload = response.json()
    assert [item['name'] for item in payload['important']] == ['knowledge-brain']
    assert [item['name'] for item in payload['secondary']] == ['graph']


@pytest.mark.asyncio
async def test_list_brain_events_returns_latest_events_first(brain_router_env):
    transport = ASGITransport(app=brain_router_env)

    async with AsyncClient(transport=transport, base_url='http://testserver') as client:
        response = await client.get('/api/brain/events')

    assert response.status_code == 200
    payload = response.json()
    assert len(payload) == 2
    assert payload[0]['title'] == 'Document indexed'
    assert payload[1]['title'] == 'Conversation created'


@pytest.mark.asyncio
async def test_manual_brain_learning_run_returns_processed_counts(brain_router_env):
    transport = ASGITransport(app=brain_router_env)

    async with AsyncClient(transport=transport, base_url='http://testserver') as client:
        response = await client.post('/api/brain/learn/run')

    assert response.status_code == 200
    payload = response.json()
    assert payload == {
        'events_considered': 1,
        'candidates_created': 1,
        'memories_promoted': 1,
    }
