import builtins

import pytest

from postgres_alembic_util import DatabaseConfig
from postgres_alembic_util._PostgresAlembicHandler import (
    _build_conn_string,
    _detect_postgres_driver,
)


@pytest.fixture
def block_imports(monkeypatch):
    """Return a helper that makes the given top-level modules unimportable."""
    real_import = builtins.__import__

    def _block(*blocked_names):
        blocked = set(blocked_names)

        def fake_import(name, globals=None, locals=None, fromlist=(), level=0):
            root = name.split(".")[0]
            if root in blocked:
                raise ImportError(f"blocked by test: {name}")
            return real_import(name, globals, locals, fromlist, level)

        monkeypatch.setattr(builtins, "__import__", fake_import)

    return _block


class TestDetectPostgresDriver:
    def test_prefers_psycopg2_when_both_installed(self):
        pytest.importorskip("psycopg2")
        pytest.importorskip("psycopg")

        assert _detect_postgres_driver() == "psycopg2"

    def test_falls_back_to_psycopg_when_psycopg2_missing(self, block_imports):
        pytest.importorskip("psycopg")
        block_imports("psycopg2")

        assert _detect_postgres_driver() == "psycopg"

    def test_raises_when_no_driver_installed(self, block_imports):
        block_imports("psycopg2", "psycopg")

        with pytest.raises(RuntimeError, match="No PostgreSQL driver found"):
            _detect_postgres_driver()


class TestBuildConnString:
    def test_uses_detected_driver_in_url(self, block_imports):
        pytest.importorskip("psycopg")
        block_imports("psycopg2")

        config = DatabaseConfig(
            host="db.example.com",
            port=5432,
            user="alice",
            password="s3cret",
            database="app",
        )

        assert (
            _build_conn_string(config)
            == "postgresql+psycopg://alice:s3cret@db.example.com:5432/app"
        )
