"""
Tests for database_init.py engine disposal.

These tests verify that SQLAlchemy engines are properly disposed in the
database initialization module to prevent file descriptor leaks.
"""

from unittest.mock import MagicMock, patch

import pytest


class TestInitDatabaseEngineDisposal:
    """Tests for engine disposal in init_database()."""

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch("local_deep_research.library.download_management.database_init.Base")
    def test_init_database_disposes_engine_on_success(
        self, mock_base, mock_create_engine
    ):
        """Test that init_database() disposes engine even on success."""
        from local_deep_research.library.download_management.database_init import (
            init_database,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        result = init_database()

        # Engine should be disposed
        mock_engine.dispose.assert_called_once()
        # Function should return None since engine is disposed
        assert result is None

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch("local_deep_research.library.download_management.database_init.Base")
    def test_init_database_disposes_engine_on_create_all_exception(
        self, mock_base, mock_create_engine
    ):
        """Test that init_database() disposes engine when create_all fails."""
        from local_deep_research.library.download_management.database_init import (
            init_database,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine
        mock_base.metadata.create_all.side_effect = Exception(
            "Table creation failed"
        )

        with pytest.raises(Exception, match="Table creation failed"):
            init_database()

        # Engine should still be disposed in finally block
        mock_engine.dispose.assert_called_once()

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch("local_deep_research.library.download_management.database_init.Base")
    def test_init_database_calls_create_all(
        self, mock_base, mock_create_engine
    ):
        """Test that init_database() calls Base.metadata.create_all()."""
        from local_deep_research.library.download_management.database_init import (
            init_database,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        init_database()

        # Should create tables
        mock_base.metadata.create_all.assert_called_once_with(mock_engine)


class TestVerifyTableExistsEngineDisposal:
    """Tests for engine disposal in verify_table_exists()."""

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch(
        "local_deep_research.library.download_management.database_init.inspect"
    )
    def test_verify_table_exists_disposes_engine_when_table_exists(
        self, mock_inspect, mock_create_engine
    ):
        """Test that verify_table_exists() disposes engine when table exists."""
        from local_deep_research.library.download_management.database_init import (
            verify_table_exists,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        mock_inspector = MagicMock()
        mock_inspector.get_table_names.return_value = [
            "resource_download_status"
        ]
        mock_inspect.return_value = mock_inspector

        result = verify_table_exists()

        # Engine should be disposed
        mock_engine.dispose.assert_called_once()
        # Should return True since table exists
        assert result is True

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch(
        "local_deep_research.library.download_management.database_init.inspect"
    )
    def test_verify_table_exists_disposes_engine_when_table_missing(
        self, mock_inspect, mock_create_engine
    ):
        """Test that verify_table_exists() disposes engine when table is missing."""
        from local_deep_research.library.download_management.database_init import (
            verify_table_exists,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        mock_inspector = MagicMock()
        mock_inspector.get_table_names.return_value = ["other_table"]
        mock_inspect.return_value = mock_inspector

        result = verify_table_exists()

        # Engine should be disposed
        mock_engine.dispose.assert_called_once()
        # Should return False since table doesn't exist
        assert result is False

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch(
        "local_deep_research.library.download_management.database_init.inspect"
    )
    def test_verify_table_exists_disposes_engine_on_inspect_exception(
        self, mock_inspect, mock_create_engine
    ):
        """Test that verify_table_exists() disposes engine on inspect error."""
        from local_deep_research.library.download_management.database_init import (
            verify_table_exists,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine
        mock_inspect.side_effect = Exception("Inspection failed")

        with pytest.raises(Exception, match="Inspection failed"):
            verify_table_exists()

        # Engine should still be disposed in finally block
        mock_engine.dispose.assert_called_once()

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch(
        "local_deep_research.library.download_management.database_init.inspect"
    )
    def test_verify_table_exists_disposes_engine_on_get_table_names_exception(
        self, mock_inspect, mock_create_engine
    ):
        """Test that verify_table_exists() disposes engine on get_table_names error."""
        from local_deep_research.library.download_management.database_init import (
            verify_table_exists,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        mock_inspector = MagicMock()
        mock_inspector.get_table_names.side_effect = Exception(
            "Cannot read tables"
        )
        mock_inspect.return_value = mock_inspector

        with pytest.raises(Exception, match="Cannot read tables"):
            verify_table_exists()

        # Engine should still be disposed in finally block
        mock_engine.dispose.assert_called_once()

    @patch(
        "local_deep_research.library.download_management.database_init.create_engine"
    )
    @patch(
        "local_deep_research.library.download_management.database_init.inspect"
    )
    def test_verify_table_exists_uses_inspect_function(
        self, mock_inspect, mock_create_engine
    ):
        """Test that verify_table_exists() uses SQLAlchemy inspect()."""
        from local_deep_research.library.download_management.database_init import (
            verify_table_exists,
        )

        mock_engine = MagicMock()
        mock_create_engine.return_value = mock_engine

        mock_inspector = MagicMock()
        mock_inspector.get_table_names.return_value = []
        mock_inspect.return_value = mock_inspector

        verify_table_exists()

        # Should call inspect with the engine
        mock_inspect.assert_called_once_with(mock_engine)
