import sqlalchemy
from sqlalchemy import text
from sqlalchemy.pool import NullPool

from postgres_alembic_util import PostgresAlembicHandler
from postgres_alembic_util._PostgresAlembicHandler import _build_conn_string


def _engine_for(db_config):
    return sqlalchemy.create_engine(_build_conn_string(db_config), poolclass=NullPool)


def _table_exists(db_config, table_name: str) -> bool:
    engine = _engine_for(db_config)
    try:
        with engine.connect() as conn:
            inspector = sqlalchemy.inspect(conn)
            return inspector.has_table(table_name)
    finally:
        engine.dispose()


class TestUpgradeAndDowngrade:
    def test_upgrade_to_head_creates_migration_tables(self, alembic_database_info, db_config):
        handler = PostgresAlembicHandler(alembic_database_info)

        handler.upgrade_to_head()

        try:
            assert _table_exists(db_config, "widgets")
            assert _table_exists(db_config, "alembic_version")
        finally:
            handler.downgrade_to_base()

    def test_upgrade_then_downgrade_leaves_no_migration_tables(self, alembic_database_info, db_config):
        handler = PostgresAlembicHandler(alembic_database_info)
        handler.upgrade_to_head()

        handler.downgrade_to_base()

        assert not _table_exists(db_config, "widgets")
        assert not _table_exists(db_config, "alembic_version")

    def test_alembic_version_records_head_revision(self, alembic_database_info, db_config):
        handler = PostgresAlembicHandler(alembic_database_info)

        handler.upgrade_to_head()

        try:
            engine = _engine_for(db_config)
            try:
                with engine.connect() as conn:
                    result = conn.execute(text("select version_num from alembic_version")).scalar()
            finally:
                engine.dispose()

            assert result == "0001"
        finally:
            handler.downgrade_to_base()

    def test_upgrade_is_idempotent_when_called_twice(self, alembic_database_info, db_config):
        handler = PostgresAlembicHandler(alembic_database_info)
        handler.upgrade_to_head()

        handler.upgrade_to_head()  # should be a no-op, not an error

        try:
            assert _table_exists(db_config, "widgets")
        finally:
            handler.downgrade_to_base()
