"""Alembic environment configuration.

Imports the application's Base and database URL so that
``alembic revision --autogenerate`` can detect model changes.
"""

from logging.config import fileConfig

from sqlalchemy import engine_from_config, pool
from alembic import context

# -- App imports -------------------------------------------------------
from app.core.config import settings
from app.core.database import Base

# Import all models so Base.metadata is fully populated
from app.models.catalog import (  # noqa: F401
    UserAccount, Session, ProjectRegistry, ProjectMember,
)
from app.models.project import (  # noqa: F401
    Episode, EntityCanon, EntityAlias, RelationFact, RelationParticipant,
    SceneStill, EntityEpisodeLink, ImageAsset, ProjectSettings, WorldGuide,
    WebbookPackage, GenerationTrace, OperationLog, PipelineProgress,
    LLMCallLog, CharacterOutlook,
)
from app.logging.models import ActivityLog  # noqa: F401

# -- Alembic Config object --------------------------------------------
config = context.config

# Override sqlalchemy.url with the value from app settings
config.set_main_option("sqlalchemy.url", settings.database_url)

# Interpret the config file for Python logging (if present)
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

target_metadata = Base.metadata


def run_migrations_offline() -> None:
    """Run migrations in 'offline' mode (emit SQL without DB connection)."""
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )
    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online() -> None:
    """Run migrations against a live database connection."""
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )
    with connectable.connect() as connection:
        _assert_canary_db_if_asked(connection)
        context.configure(connection=connection, target_metadata=target_metadata)
        with context.begin_transaction():
            context.run_migrations()


def _assert_canary_db_if_asked(connection) -> None:
    """★★canary 주행이면 **이 연결 안에서** 어느 DB 인지 확인한다.

    `THEROAD_CANARY_RUN_ID` 가 **있을 때만** 본다 — 없으면 기존 동작 그대로다.

    이 파일이 `settings.database_url` 로 URL 을 덮으므로(위 32행), 바깥에서
    아무리 잠가도 **여기서 딴 DB 로 갈 수 있다.** 그래서 확인은 **migration
    SQL 이 한 줄이라도 나가기 전에** 여기서 한다 (Codex 2026-08-31).
    """
    import os

    run_id = os.environ.get("THEROAD_CANARY_RUN_ID")
    if not run_id:
        return
    from sqlalchemy import text

    from tools.grounding_audit.canary_isolation import (
        assert_migration_connection)

    now = connection.execute(text("SELECT current_database()")).scalar()
    # ★★★읽기만 해도 **트랜잭션이 열린다.** 그대로 두면 alembic 의
    #  `begin_transaction()` 이 그 위에 얹혀 **migration 이 통째로 롤백**된다
    #  (실측 2026-08-31: `stamp` 가 「했다」고 찍고도 표가 안 생겼다).
    #  확인은 같은 연결에서 하되, **연 것은 닫는다**.
    connection.rollback()
    assert_migration_connection(run_id, current_database=now)


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
