"""Integration tests for ODBC driver utilities with SQLServerConnectionConfig."""

from unittest.mock import MagicMock, patch

import pytest

from data_exchange_agent.config.sections.connections.odbc import (
    SQLServerConnectionConfig,
    get_best_sqlserver_driver,
    get_sqlserver_drivers,
    is_driver_available,
    validate_sqlserver_driver,
)


@pytest.fixture
def mock_available_drivers():
    """Mock available SQL Server drivers."""
    return [
        "ODBC Driver 18 for SQL Server",
        "ODBC Driver 17 for SQL Server",
        "PostgreSQL Unicode",
    ]


class TestOdbcDriverUtilsIntegration:
    """Integration tests for ODBC driver utilities with SQLServerConnectionConfig."""

    def test_create_config_with_auto_detected_driver(self, mock_available_drivers):
        """Test creating a config with auto-detected driver."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            # Get best driver
            best_driver = get_best_sqlserver_driver()
            assert best_driver == "ODBC Driver 18 for SQL Server"

            # Create config with auto-detected driver
            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=best_driver,
            )

            assert config.odbc_driver == "ODBC Driver 18 for SQL Server"
            assert "ODBC Driver 18 for SQL Server" in config.build_connection_string()

    def test_create_config_with_fallback_driver(self):
        """Test creating config with fallback when driver 18 is not available."""
        drivers = ["ODBC Driver 17 for SQL Server", "PostgreSQL Unicode"]
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            best_driver = get_best_sqlserver_driver()
            assert best_driver == "ODBC Driver 17 for SQL Server"

            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=best_driver,
            )

            assert config.odbc_driver == "ODBC Driver 17 for SQL Server"

    def test_create_config_with_specific_driver(self, mock_available_drivers):
        """Test creating config with a specific driver version."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            # Verify driver is available
            assert is_driver_available("ODBC Driver 17 for SQL Server")

            # Create config with specific driver
            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver="ODBC Driver 17 for SQL Server",
            )

            assert config.odbc_driver == "ODBC Driver 17 for SQL Server"
            assert "ODBC Driver 17 for SQL Server" in config.build_connection_string()

    def test_validate_before_creating_config(self, mock_available_drivers):
        """Test validating a driver before creating config."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            driver_to_use = "ODBC Driver 18 for SQL Server"

            # Validate first
            is_valid, message = validate_sqlserver_driver(driver_to_use)
            assert is_valid
            assert "available" in message.lower()

            # Create config after validation
            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=driver_to_use,
            )

            assert config.odbc_driver == driver_to_use

    def test_list_and_choose_driver(self, mock_available_drivers):
        """Test listing drivers and choosing one."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            # List available drivers
            sqlserver_drivers = get_sqlserver_drivers()
            assert len(sqlserver_drivers) == 2
            assert "ODBC Driver 18 for SQL Server" in sqlserver_drivers
            assert "ODBC Driver 17 for SQL Server" in sqlserver_drivers

            # Choose the second one
            chosen_driver = sqlserver_drivers[1]
            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=chosen_driver,
            )

            assert config.odbc_driver == "ODBC Driver 17 for SQL Server"

    def test_config_with_default_driver_when_none_specified(self):
        """Test that config uses default driver when none is specified and auto_detect is disabled."""
        config = SQLServerConnectionConfig(
            database="testdb",
            host="localhost",
            username="sa",
            password="password",
            # odbc_driver not specified, should use default
            auto_detect_driver=False,  # Disable auto-detect to avoid requiring ODBC drivers
        )

        # Default is "ODBC Driver 18 for SQL Server"
        assert config.odbc_driver == "ODBC Driver 18 for SQL Server"

    def test_config_with_custom_driver_name(self, mock_available_drivers):
        """Test config with a custom driver name falls back to available."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            custom_driver = "Custom SQL Server Driver v99"
            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=custom_driver,
            )

            # Falls back to best available since custom driver doesn't exist
            assert config.odbc_driver == "ODBC Driver 18 for SQL Server"

    def test_windows_auth_with_auto_detected_driver(self, mock_available_drivers):
        """Test Windows authentication with auto-detected driver."""
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = mock_available_drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            best_driver = get_best_sqlserver_driver()

            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                use_windows_auth=True,
                odbc_driver=best_driver,
            )

            assert config.odbc_driver == "ODBC Driver 18 for SQL Server"
            assert config.use_windows_auth is True
            conn_str = config.build_connection_string()
            assert "Trusted_Connection=yes" in conn_str
            assert "ODBC Driver 18 for SQL Server" in conn_str

    def test_config_with_driver_13(self):
        """Test config with ODBC Driver 13."""
        drivers = [
            "ODBC Driver 13 for SQL Server",
            "PostgreSQL Unicode",
        ]
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            best_driver = get_best_sqlserver_driver()
            assert best_driver == "ODBC Driver 13 for SQL Server"

            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=best_driver,
            )

            assert config.odbc_driver == "ODBC Driver 13 for SQL Server"

    def test_config_with_native_client(self):
        """Test config with SQL Server Native Client."""
        drivers = [
            "SQL Server Native Client 11.0",
            "PostgreSQL Unicode",
        ]
        with patch("shared.odbc.driver_utils._get_pyodbc") as mock_get_pyodbc:
            mock_pyodbc = MagicMock()
            mock_pyodbc.drivers.return_value = drivers
            mock_get_pyodbc.return_value = mock_pyodbc

            best_driver = get_best_sqlserver_driver()
            assert best_driver == "SQL Server Native Client 11.0"

            config = SQLServerConnectionConfig(
                database="testdb",
                host="localhost",
                username="sa",
                password="password",
                odbc_driver=best_driver,
            )

            assert config.odbc_driver == "SQL Server Native Client 11.0"
            assert "SQL Server Native Client 11.0" in config.build_connection_string()
