"""Tests for auth_db module."""

import tempfile
from pathlib import Path
from unittest.mock import patch, Mock


class TestGetAuthDbPath:
    """Tests for get_auth_db_path function."""

    def test_returns_path_object(self):
        """get_auth_db_path returns a Path object."""
        from local_deep_research.database.auth_db import get_auth_db_path

        with patch(
            "local_deep_research.database.auth_db.get_data_directory"
        ) as mock_get_data:
            mock_get_data.return_value = Path("/fake/data/dir")

            result = get_auth_db_path()

            assert isinstance(result, Path)

    def test_returns_correct_filename(self):
        """get_auth_db_path returns path with ldr_auth.db filename."""
        from local_deep_research.database.auth_db import get_auth_db_path

        with patch(
            "local_deep_research.database.auth_db.get_data_directory"
        ) as mock_get_data:
            mock_get_data.return_value = Path("/fake/data/dir")

            result = get_auth_db_path()

            assert result.name == "ldr_auth.db"

    def test_uses_data_directory(self):
        """get_auth_db_path uses get_data_directory for parent path."""
        from local_deep_research.database.auth_db import get_auth_db_path

        with patch(
            "local_deep_research.database.auth_db.get_data_directory"
        ) as mock_get_data:
            mock_get_data.return_value = Path("/test/data/path")

            result = get_auth_db_path()

            mock_get_data.assert_called_once()
            assert result.parent == Path("/test/data/path")


class TestInitAuthDatabase:
    """Tests for init_auth_database function."""

    def test_creates_database_directory(self):
        """init_auth_database creates parent directory if needed."""
        from local_deep_research.database.auth_db import init_auth_database

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "subdir" / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.create_engine"
                ) as mock_engine:
                    mock_engine_instance = Mock()
                    mock_engine.return_value = mock_engine_instance

                    with patch("local_deep_research.database.auth_db.Base"):
                        init_auth_database()

                # Directory should be created
                assert db_path.parent.exists()

    def test_skips_if_database_exists(self):
        """init_auth_database skips creation if database already exists."""
        from local_deep_research.database.auth_db import init_auth_database

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"
            # Create the file
            db_path.touch()

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.create_engine"
                ) as mock_engine:
                    init_auth_database()

                    # create_engine should not be called
                    mock_engine.assert_not_called()

    def test_creates_tables(self):
        """init_auth_database creates User table."""
        from local_deep_research.database.auth_db import init_auth_database

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.create_engine"
                ) as mock_engine:
                    mock_engine_instance = Mock()
                    mock_engine.return_value = mock_engine_instance

                    with patch(
                        "local_deep_research.database.auth_db.Base"
                    ) as mock_base:
                        with patch(
                            "local_deep_research.database.auth_db.User"
                        ) as mock_user:
                            mock_user.__table__ = Mock()

                            init_auth_database()

                            # Should call create_all with User table
                            mock_base.metadata.create_all.assert_called_once()


class TestGetAuthDbSession:
    """Tests for get_auth_db_session function."""

    def test_returns_session(self):
        """get_auth_db_session returns a SQLAlchemy session."""
        from local_deep_research.database.auth_db import get_auth_db_session

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"
            # Create the file so init is skipped
            db_path.touch()

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.create_engine"
                ) as mock_engine:
                    mock_engine_instance = Mock()
                    mock_engine.return_value = mock_engine_instance

                    with patch(
                        "local_deep_research.database.auth_db.sessionmaker"
                    ) as mock_sessionmaker:
                        mock_session_class = Mock()
                        mock_session = Mock()
                        mock_session_class.return_value = mock_session
                        mock_sessionmaker.return_value = mock_session_class

                        result = get_auth_db_session()

                        assert result is mock_session

    def test_creates_database_if_missing(self):
        """get_auth_db_session initializes database if it doesn't exist."""
        from local_deep_research.database.auth_db import get_auth_db_session

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"
            # Don't create the file - it doesn't exist

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.init_auth_database"
                ) as mock_init:
                    with patch(
                        "local_deep_research.database.auth_db.create_engine"
                    ) as mock_engine:
                        mock_engine_instance = Mock()
                        mock_engine.return_value = mock_engine_instance

                        with patch(
                            "local_deep_research.database.auth_db.sessionmaker"
                        ) as mock_sessionmaker:
                            mock_session_class = Mock()
                            mock_session = Mock()
                            mock_session_class.return_value = mock_session
                            mock_sessionmaker.return_value = mock_session_class

                            get_auth_db_session()

                            # init_auth_database should be called
                            mock_init.assert_called_once()

    def test_creates_engine_with_correct_url(self):
        """get_auth_db_session creates engine with correct SQLite URL."""
        from local_deep_research.database.auth_db import get_auth_db_session

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"
            db_path.touch()

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                with patch(
                    "local_deep_research.database.auth_db.create_engine"
                ) as mock_engine:
                    mock_engine_instance = Mock()
                    mock_engine.return_value = mock_engine_instance

                    with patch(
                        "local_deep_research.database.auth_db.sessionmaker"
                    ) as mock_sessionmaker:
                        mock_session_class = Mock()
                        mock_session = Mock()
                        mock_session_class.return_value = mock_session
                        mock_sessionmaker.return_value = mock_session_class

                        get_auth_db_session()

                        # Verify create_engine was called with sqlite URL
                        call_args = mock_engine.call_args[0][0]
                        assert call_args.startswith("sqlite:///")
                        assert "ldr_auth.db" in call_args


class TestAuthDbEngineCache:
    """Tests for cached engine behavior."""

    def test_get_auth_engine_returns_engine(self):
        """Test that _get_auth_engine() returns an engine."""
        from local_deep_research.database.auth_db import (
            _get_auth_engine,
            dispose_auth_engine,
        )

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                # Ensure we start with a clean state
                dispose_auth_engine()

                engine = _get_auth_engine()

                assert engine is not None

                # Clean up
                dispose_auth_engine()

    def test_engine_cached_on_subsequent_calls(self):
        """Test that _get_auth_engine() returns cached engine."""
        from local_deep_research.database.auth_db import (
            _get_auth_engine,
            dispose_auth_engine,
        )

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                # Ensure we start with a clean state
                dispose_auth_engine()

                engine1 = _get_auth_engine()
                engine2 = _get_auth_engine()

                # Should return the same cached engine
                assert engine1 is engine2

                # Clean up
                dispose_auth_engine()

    def test_engine_recreated_on_path_change(self):
        """Test that engine is recreated when data directory changes."""
        from local_deep_research.database.auth_db import (
            _get_auth_engine,
            dispose_auth_engine,
        )

        with tempfile.TemporaryDirectory() as temp_dir1:
            with tempfile.TemporaryDirectory() as temp_dir2:
                db_path1 = Path(temp_dir1) / "ldr_auth.db"
                db_path2 = Path(temp_dir2) / "ldr_auth.db"

                # Ensure we start with a clean state
                dispose_auth_engine()

                with patch(
                    "local_deep_research.database.auth_db.get_auth_db_path"
                ) as mock_path:
                    # First call with path1
                    mock_path.return_value = db_path1
                    engine1 = _get_auth_engine()

                    # Change to path2
                    mock_path.return_value = db_path2
                    engine2 = _get_auth_engine()

                    # Should be different engines
                    assert engine1 is not engine2

                    # Clean up
                    dispose_auth_engine()

    def test_dispose_clears_cache(self):
        """Test that dispose_auth_engine() clears the cached engine."""
        from local_deep_research.database import auth_db
        from local_deep_research.database.auth_db import (
            _get_auth_engine,
            dispose_auth_engine,
        )

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                # Ensure we start with a clean state
                dispose_auth_engine()

                # Create an engine
                _get_auth_engine()

                # Dispose it
                dispose_auth_engine()

                # Module-level _auth_engine should be None
                assert auth_db._auth_engine is None

    def test_dispose_clears_path(self):
        """Test that dispose_auth_engine() clears the cached path."""
        from local_deep_research.database import auth_db
        from local_deep_research.database.auth_db import (
            _get_auth_engine,
            dispose_auth_engine,
        )

        with tempfile.TemporaryDirectory() as temp_dir:
            db_path = Path(temp_dir) / "ldr_auth.db"

            with patch(
                "local_deep_research.database.auth_db.get_auth_db_path"
            ) as mock_path:
                mock_path.return_value = db_path

                # Ensure we start with a clean state
                dispose_auth_engine()

                # Create an engine
                _get_auth_engine()

                # Dispose it
                dispose_auth_engine()

                # Module-level _auth_engine_path should be None
                assert auth_db._auth_engine_path is None

    def test_dispose_handles_no_engine(self):
        """Test that dispose_auth_engine() handles no engine gracefully."""
        from local_deep_research.database.auth_db import dispose_auth_engine

        # Dispose when there's no engine should not raise
        dispose_auth_engine()
        dispose_auth_engine()  # Calling twice should be fine
