"""
Alembic 環境設定。

主要工作:
  1. 從 app.config 讀取 DATABASE_URL(支援 .env)
  2. 註冊所有 Model 的 metadata,讓 --autogenerate 偵測到新增/變更
  3. 提供 online migration(實際連到資料庫執行)的進入點

注意:asyncpg 是 async driver,但 Alembic 本體是 sync,
所以 online migration 內部會用 SQLAlchemy 的 async runner 包一層。
"""

import asyncio
from logging.config import fileConfig

from alembic import context
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config

from app.config import settings
# 重要:import models 才能讓 Base.metadata 看到所有資料表
from app.database import Base
import app.models  # noqa: F401


# Alembic 設定物件
config = context.config

# 把 .env 讀到的 DATABASE_URL 注入給 Alembic 用
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL)

# 設定 Python logging
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

# Migration 偵測用的 metadata
target_metadata = Base.metadata


def run_migrations_offline() -> None:
    """Offline mode:不實際連資料庫,只產生 SQL 檔案。

    很少用到,主要在沒有 DB 連線的 CI 環境會用。
    """
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
        compare_type=True,           # 偵測欄位型別變更
        compare_server_default=True, # 偵測 default 值變更
    )

    with context.begin_transaction():
        context.run_migrations()


def do_run_migrations(connection: Connection) -> None:
    """實際執行 migration 的 sync 函式(由 async runner 呼叫)。"""
    context.configure(
        connection=connection,
        target_metadata=target_metadata,
        compare_type=True,
        compare_server_default=True,
    )

    with context.begin_transaction():
        context.run_migrations()


async def run_async_migrations() -> None:
    """Online mode:用 async engine 連線,執行 migration。"""
    connectable = async_engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    async with connectable.connect() as connection:
        await connection.run_sync(do_run_migrations)

    await connectable.dispose()


def run_migrations_online() -> None:
    """Alembic 預設進入點。"""
    asyncio.run(run_async_migrations())


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