"""Test multi-user encrypted database functionality."""

import shutil
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from local_deep_research.database.encrypted_db import DatabaseManager
from local_deep_research.database.models import (
    ResearchHistory,
)
from local_deep_research.database.models.auth import User


class TestMultiUserDatabase:
    """Test suite for multi-user encrypted database functionality."""

    @pytest.fixture
    def temp_dir(self):
        """Create a temporary directory for test databases."""
        temp_dir = tempfile.mkdtemp()
        yield temp_dir
        shutil.rmtree(temp_dir)

    @pytest.fixture
    def db_manager(self, temp_dir):
        """Create a database manager with a custom data directory."""
        # Mock the data directory to use our temp directory
        with patch(
            "local_deep_research.database.encrypted_db.get_data_directory"
        ) as mock_get_dir:
            mock_get_dir.return_value = Path(temp_dir)
            manager = DatabaseManager()
            manager.data_dir = Path(temp_dir) / "encrypted_databases"
            manager.data_dir.mkdir(parents=True, exist_ok=True)
            yield manager

    @pytest.fixture
    def mock_auth_db(self, monkeypatch):
        """Mock the auth database functions."""
        mock_session = MagicMock()
        mock_user = MagicMock(spec=User)
        mock_user.username = "testuser"

        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_user
        mock_session.close = MagicMock()

        def mock_get_auth_db_session():
            return mock_session

        monkeypatch.setattr(
            "local_deep_research.database.auth_db.get_auth_db_session",
            mock_get_auth_db_session,
        )

        return mock_session

    def test_database_isolation_without_sqlcipher(
        self, db_manager, mock_auth_db
    ):
        """Test that the system handles missing SQLCipher gracefully."""
        # This test verifies the system's behavior when SQLCipher is not available
        # In a real deployment, SQLCipher would be required

        # Mock SQLAlchemy to simulate SQLCipher not being available
        with patch(
            "local_deep_research.database.encrypted_db.create_engine"
        ) as mock_engine:
            mock_engine.side_effect = ImportError(
                "No module named 'pysqlcipher3'"
            )

            # Attempt to create a user database
            with pytest.raises(ImportError):
                db_manager.create_user_database("testuser", "password123")

    def test_user_exists_check(self, db_manager, mock_auth_db):
        """Test checking if a user exists."""
        # Test existing user
        assert db_manager.user_exists("testuser") is True

        # Test non-existing user
        mock_auth_db.query.return_value.filter_by.return_value.first.return_value = None
        assert db_manager.user_exists("nonexistent") is False

    def test_database_path_generation(self, db_manager):
        """Test that database paths are generated correctly."""
        # Test path generation for different usernames
        path1 = db_manager._get_user_db_path("user1")
        path2 = db_manager._get_user_db_path("user2")

        # Paths should be different
        assert path1 != path2

        # Paths should be in the correct directory
        assert path1.parent == db_manager.data_dir
        assert path2.parent == db_manager.data_dir

        # Paths should use hashed usernames
        assert "user1" not in str(path1)
        assert "user2" not in str(path2)

    def test_memory_usage_tracking(self, db_manager):
        """Test memory usage statistics."""
        stats = db_manager.get_memory_usage()

        assert stats["active_connections"] == 0
        assert stats["active_sessions"] == 0
        assert stats["estimated_memory_mb"] == 0

    def test_session_management_without_sqlcipher(self, db_manager):
        """Test session management when SQLCipher is not available."""
        # Without an open database, get_session should return None
        session = db_manager.get_session("testuser")
        assert session is None

    @pytest.mark.skipif(
        True,  # Always skip for now since SQLCipher is not installed
        reason="SQLCipher not available in test environment",
    )
    def test_full_multiuser_flow(self, db_manager, mock_auth_db):
        """Test complete multi-user flow with SQLCipher (skipped if not available)."""
        # This test would run if SQLCipher were installed

        # Create databases for two users

        # Get sessions for each user
        session1 = db_manager.get_session("user1")
        session2 = db_manager.get_session("user2")

        # Add research to user1's database
        research1 = ResearchHistory(
            query="User 1 research", mode="quick", status="completed"
        )
        session1.add(research1)
        session1.commit()

        # Add research to user2's database
        research2 = ResearchHistory(
            query="User 2 research", mode="deep", status="completed"
        )
        session2.add(research2)
        session2.commit()

        # Verify isolation - each user only sees their own data
        user1_research = session1.query(ResearchHistory).all()
        user2_research = session2.query(ResearchHistory).all()

        assert len(user1_research) == 1
        assert len(user2_research) == 1
        assert user1_research[0].query == "User 1 research"
        assert user2_research[0].query == "User 2 research"

        # Test password change
        success = db_manager.change_password(
            "user1", "password1", "newpassword1"
        )
        assert success is True

        # Close databases
        db_manager.close_user_database("user1")
        db_manager.close_user_database("user2")

        # Verify databases are closed
        assert "user1" not in db_manager.connections
        assert "user2" not in db_manager.connections
