"""Tests for WarehouseAdapter (mocked sqlalchemy)."""
import sys
import types
import pytest
from unittest.mock import MagicMock, patch


def _make_mock_sqlalchemy():
    """Create a minimal mock sqlalchemy module tree."""
    sa = types.ModuleType("sqlalchemy")
    sa.create_engine = MagicMock()
    sa.inspect = MagicMock()
    sa.text = MagicMock(side_effect=lambda s: s)
    return sa


@pytest.fixture(autouse=True)
def _mock_sqlalchemy(monkeypatch):
    """Inject a mock sqlalchemy into sys.modules for the test session."""
    mock_sa = _make_mock_sqlalchemy()
    monkeypatch.setitem(sys.modules, "sqlalchemy", mock_sa)
    import importlib
    import kanoniv.adapters.warehouse as wh_mod
    importlib.reload(wh_mod)
    yield mock_sa


class TestWarehouseAdapter:
    def test_lazy_connection(self):
        """Engine should not be created during __init__."""
        from kanoniv.adapters.warehouse import WarehouseAdapter

        adapter = WarehouseAdapter(
            "analytics.customers",
            connection_string="sqlite:///test.db",
        )
        assert adapter._engine is None

    def test_missing_connection_string(self):
        from kanoniv.adapters.warehouse import WarehouseAdapter

        adapter = WarehouseAdapter("some_table")
        with pytest.raises(ValueError, match="connection_string"):
            adapter.schema()

    def test_schema_reflection(self, _mock_sqlalchemy):
        """schema() should reflect columns from sqlalchemy inspector."""
        from kanoniv.adapters.warehouse import WarehouseAdapter

        mock_inspector = MagicMock()

        int_type = MagicMock()
        type(int_type).__name__ = "INTEGER"
        str_type = MagicMock()
        type(str_type).__name__ = "VARCHAR"
        bool_type = MagicMock()
        type(bool_type).__name__ = "BOOLEAN"

        mock_inspector.get_columns.return_value = [
            {"name": "id", "type": int_type, "nullable": False},
            {"name": "name", "type": str_type, "nullable": True},
            {"name": "active", "type": bool_type, "nullable": False},
        ]

        # Make sqlalchemy.inspect return our mock inspector
        _mock_sqlalchemy.inspect = MagicMock(return_value=mock_inspector)

        adapter = WarehouseAdapter(
            "public.users",
            connection_string="postgresql://localhost/test",
        )
        # Inject engine directly to avoid create_engine call
        adapter._engine = MagicMock()

        schema = adapter.schema()

        assert len(schema.columns) == 3
        col_map = {c.name: c for c in schema.columns}
        assert col_map["id"].dtype == "number"
        assert col_map["name"].dtype == "string"
        assert col_map["active"].dtype == "boolean"
        assert col_map["id"].nullable is False

    def test_import_error_message(self, monkeypatch):
        """Should give a clear error if sqlalchemy is not installed."""
        monkeypatch.setitem(sys.modules, "sqlalchemy", None)

        import importlib
        import kanoniv.adapters.warehouse as wh_mod
        importlib.reload(wh_mod)

        with pytest.raises(ImportError, match="sqlalchemy"):
            wh_mod.WarehouseAdapter("test_table", connection_string="sqlite:///test.db")
