"""
Alembic migration environment — async SQLAlchemy configuration.

Uses asyncpg driver with asyncio migration pattern required for SQLAlchemy 2.0.
Runs migrations as the postgres admin user (DATABASE_ADMIN_URL) so it can:
  - CREATE ROLE konstruct_app
  - ENABLE ROW LEVEL SECURITY
  - FORCE ROW LEVEL SECURITY
  - CREATE POLICY

Application code always uses DATABASE_URL (konstruct_app role).
"""

from __future__ import annotations

import asyncio
import os
import sys
from logging.config import fileConfig

from alembic import context
from sqlalchemy.ext.asyncio import create_async_engine

# ---------------------------------------------------------------------------
# Make sure packages/shared is importable when running `alembic upgrade head`
# from the repo root.
# ---------------------------------------------------------------------------
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from shared.models.tenant import Base  # noqa: E402  # type: ignore[import]

# Import auth model to register it with Base.metadata
import shared.models.auth  # noqa: E402, F401  # type: ignore[import]

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

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

# ---------------------------------------------------------------------------
# Metadata for autogenerate support
# ---------------------------------------------------------------------------
target_metadata = Base.metadata

# ---------------------------------------------------------------------------
# Use DATABASE_ADMIN_URL if set (for CI / production migrations),
# otherwise fall back to alembic.ini sqlalchemy.url.
# ---------------------------------------------------------------------------
database_url = os.environ.get("DATABASE_ADMIN_URL") or config.get_main_option("sqlalchemy.url")


def run_migrations_offline() -> None:
    """
    Run migrations in 'offline' mode.

    This configures the context with just a URL and not an Engine.
    Useful for generating SQL scripts without a live DB connection.
    """
    context.configure(
        url=database_url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )

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


async def run_async_migrations() -> None:
    """
    Create an async engine and run migrations within an async context.

    This is the required pattern for SQLAlchemy 2.0 + asyncpg.
    """
    connectable = create_async_engine(database_url, echo=False)

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

    await connectable.dispose()


def do_run_migrations(connection: object) -> None:
    """Synchronous migration runner — called within async context."""
    context.configure(connection=connection, target_metadata=target_metadata)  # type: ignore[arg-type]

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


def run_migrations_online() -> None:
    """Run migrations in 'online' mode with a live DB connection."""
    asyncio.run(run_async_migrations())


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