"""
Integration test for user session reloads with user model.

This test validates the CRITICAL requirement:
User profiles generated by dreaming worker MUST be available in subsequent sessions.

Test Flow:
1. User creates Session A with some messages
2. Dreaming worker runs update_user_model() - generates profile from activity
3. User creates Session B (new session)
4. Session B loads and should have:
   - Previous message history (from Session A via compressed sessions)
   - User profile (from User entity, queryable by user_id/name)

Success Criteria:
- User profile persists across sessions
- Profile updates without losing existing user data (upsert behavior)
- Session context includes user profile for agent use
- Compressed sessions provide message history continuity
"""

import pytest
from datetime import datetime, timedelta, timezone

from rem.models.entities.message import Message
from rem.models.entities.resource import Resource
from rem.models.entities.user import User
from rem.services.postgres.repository import Repository
from rem.services.postgres.service import PostgresService
from rem.workers.dreaming import DreamingWorker


@pytest.mark.asyncio
@pytest.mark.integration
@pytest.mark.skipif(
    condition=True,  # Skip by default - requires DB setup
    reason="Requires PostgreSQL database"
)
async def test_user_profile_persists_across_sessions():
    """
    Test that user profile generated by dreaming worker is available in subsequent sessions.

    This validates the core requirement:
    - User profile stored in User entity
    - Profile queryable by user_id
    - Profile includes summary, interests, preferred_topics, activity_level
    - Upsert behavior preserves existing data
    """
    # Test configuration
    USER_ID = "test-user-session-reload"
    TENANT_ID = "test-tenant-session-reload"
    USER_NAME = "test-user-session-reload"  # User.name is the entity_key

    # Initialize database
    db = PostgresService()
    await db.connect()

    try:
        # Create repositories
        session_repo = Repository(Session, "sessions", db=db)
        resource_repo = Repository(Resource, "resources", db=db)
        user_repo = Repository(User, "users", db=db)

        # ===== STEP 1: Create Session A with activity =====
        print("\n=== Step 1: Create Session A ===")

        # Create some resources (user's work)
        resource1 = Resource(
            id="resource-1",
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            name="API Design Document",
            category="documentation",
            content="Detailed design for GraphQL API migration. Discusses Apollo Server setup, schema design, and federation patterns.",
            resource_timestamp=datetime.now(timezone.utc) - timedelta(hours=2),
            created_at=datetime.now(timezone.utc) - timedelta(hours=2),
            updated_at=datetime.now(timezone.utc) - timedelta(hours=2),
        )
        await resource_repo.upsert(resource1)

        resource2 = Resource(
            id="resource-2",
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            name="TiDB Migration Plan",
            category="documentation",
            content="Planning document for migrating from PostgreSQL to TiDB. Covers scaling benefits, compatibility analysis, and migration timeline.",
            resource_timestamp=datetime.now(timezone.utc) - timedelta(hours=1),
            created_at=datetime.now(timezone.utc) - timedelta(hours=1),
            updated_at=datetime.now(timezone.utc) - timedelta(hours=1),
        )
        await resource_repo.upsert(resource2)

        # Create Session A with conversation
        session_a = Session(
            id="session-a",
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            query="How should I structure the GraphQL schema for our customer API?",
            response="I recommend using a federated schema approach with Apollo Federation. This allows you to split your schema across microservices while maintaining a unified API...",
            metadata={"session_name": "GraphQL Design Discussion"},
            created_at=datetime.now(timezone.utc) - timedelta(minutes=30),
            updated_at=datetime.now(timezone.utc) - timedelta(minutes=30),
        )
        await session_repo.upsert(session_a)

        print(f"✓ Created Session A: {session_a.id}")
        print(f"✓ Created 2 resources")

        # ===== STEP 2: Run dreaming worker to generate user profile =====
        print("\n=== Step 2: Generate User Profile ===")

        worker = DreamingWorker()
        try:
            result = await worker.update_user_model(
                user_id=USER_ID,
                tenant_id=TENANT_ID,
                time_window_days=1,  # Look at last 24 hours
                max_sessions=100,
                max_moments=20,
                max_resources=20,
            )

            assert result["status"] == "success", f"Profile generation failed: {result}"
            assert result["user_updated"] == True
            print(f"✓ User model updated")
            print(f"  Sessions analyzed: {result['sessions_analyzed']}")
            print(f"  Resources included: {result['resources_included']}")
            print(f"  Current projects: {result['current_projects']}")

        finally:
            await worker.close()

        # ===== STEP 3: Verify User entity exists with profile =====
        print("\n=== Step 3: Verify User Profile ===")

        user = await user_repo.get_by_id(USER_ID, TENANT_ID)
        assert user is not None, "User entity should exist after profile generation"

        # Verify User model fields
        assert user.summary is not None, "User should have summary"
        assert len(user.summary) > 0, "Summary should not be empty"
        assert user.interests is not None, "User should have interests"
        assert user.preferred_topics is not None, "User should have preferred topics"
        assert user.activity_level in ["active", "moderate", "inactive"], "User should have activity level"
        assert user.last_active_at is not None, "User should have last_active_at"

        # Verify metadata.profile
        assert "profile" in user.metadata, "User metadata should have profile"
        profile = user.metadata["profile"]
        assert "summary" in profile, "Profile should have summary"
        assert "current_projects" in profile, "Profile should have current_projects"
        assert "technical_stack" in profile, "Profile should have technical_stack"
        assert "recommended_tags" in profile, "Profile should have recommended_tags"

        print(f"✓ User profile verified")
        print(f"  Summary: {user.summary[:100]}...")
        print(f"  Interests: {user.interests[:3]}")
        print(f"  Preferred topics: {user.preferred_topics[:5]}")
        print(f"  Activity level: {user.activity_level}")
        print(f"  Projects: {len(profile['current_projects'])}")

        # ===== STEP 4: Create Session B - should have user profile available =====
        print("\n=== Step 4: Create Session B (with profile) ===")

        # In real system, Session B loading would:
        # 1. Query User entity by user_id
        # 2. Include user.summary and user.metadata.profile in session context
        # 3. Load compressed sessions for message history
        # 4. Agent receives user context in system prompt or via lookup

        # Simulate session loading
        user_for_session = await user_repo.get_by_id(USER_ID, TENANT_ID)

        session_b = Session(
            id="session-b",
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            query="What are the next steps for the TiDB migration?",
            response=f"Based on your profile, I see you're working on TiDB migration. Given your background in {user_for_session.preferred_topics[0] if user_for_session.preferred_topics else 'database systems'}, I recommend...",
            metadata={
                "session_name": "TiDB Migration Follow-up",
                "user_profile_loaded": True,
                "user_summary": user_for_session.summary[:200],  # Include in session context
            },
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        await session_repo.upsert(session_b)

        print(f"✓ Created Session B: {session_b.id}")
        print(f"✓ User profile available in session context")
        print(f"  Summary snippet: {session_b.metadata['user_summary'][:100]}...")

        # ===== STEP 5: Update profile again (upsert behavior test) =====
        print("\n=== Step 5: Test Upsert Behavior ===")

        # Create another resource
        resource3 = Resource(
            id="resource-3",
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            name="Kubernetes Autoscaling Config",
            category="configuration",
            content="HPA configuration for rem-api deployment with CPU and memory-based scaling.",
            resource_timestamp=datetime.now(timezone.utc),
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        await resource_repo.upsert(resource3)

        # Run profile update again
        worker2 = DreamingWorker()
        try:
            result2 = await worker2.update_user_model(
                user_id=USER_ID,
                tenant_id=TENANT_ID,
                time_window_days=1,
            )

            assert result2["status"] == "success"
            assert result2["user_updated"] == True

        finally:
            await worker2.close()

        # Verify user still exists (not recreated)
        user_after_update = await user_repo.get_by_id(USER_ID, TENANT_ID)
        assert user_after_update is not None
        assert user_after_update.id == user.id  # Same user
        assert user_after_update.created_at == user.created_at  # Preserves creation time
        assert user_after_update.summary != user.summary or True  # May have updated summary

        print(f"✓ Upsert behavior verified")
        print(f"  User ID preserved: {user_after_update.id == user.id}")
        print(f"  Created at preserved: {user_after_update.created_at == user.created_at}")

        # ===== CLEANUP =====
        print("\n=== Cleanup ===")
        await session_repo.delete(session_a.id, TENANT_ID)
        await session_repo.delete(session_b.id, TENANT_ID)
        await resource_repo.delete(resource1.id, TENANT_ID)
        await resource_repo.delete(resource2.id, TENANT_ID)
        await resource_repo.delete(resource3.id, TENANT_ID)
        await user_repo.delete(user.id, TENANT_ID)
        print("✓ Cleanup complete")

    finally:
        await db.disconnect()


@pytest.mark.asyncio
@pytest.mark.integration
@pytest.mark.skipif(
    condition=True,
    reason="Requires PostgreSQL database and LLM API"
)
async def test_user_profile_queryable_by_name():
    """
    Test that User entity can be queried by name (entity_key).

    This validates:
    - User.name is the primary business key
    - Can query by name for session context loading
    - Name-based lookup enables natural language references
    """
    USER_ID = "test-user-name-query"
    TENANT_ID = "test-tenant"
    USER_NAME = "sarah-chen"  # Natural name as key

    db = PostgresService()
    await db.connect()

    try:
        user_repo = Repository(User, "users", db=db)

        # Create user with name
        user = User(
            id=USER_ID,
            tenant_id=TENANT_ID,
            user_id=USER_ID,
            name=USER_NAME,
            summary="Test user for name-based lookup",
            created_at=datetime.now(timezone.utc),
            updated_at=datetime.now(timezone.utc),
        )
        await user_repo.upsert(user)

        # Query by ID
        user_by_id = await user_repo.get_by_id(USER_ID, TENANT_ID)
        assert user_by_id is not None
        assert user_by_id.name == USER_NAME

        # In future: Query by name (requires REM LOOKUP)
        # user_by_name = await rem_service.lookup("users", USER_NAME, TENANT_ID)
        # assert user_by_name is not None
        # assert user_by_name.id == USER_ID

        print(f"✓ User queryable by ID: {user_by_id.id}")
        print(f"✓ User name: {user_by_id.name}")

        # Cleanup
        await user_repo.delete(user.id, TENANT_ID)

    finally:
        await db.disconnect()


if __name__ == "__main__":
    """Run test manually for debugging."""
    import asyncio

    asyncio.run(test_user_profile_persists_across_sessions())
