from __future__ import annotations

import asyncio
import sys
from logging.config import fileConfig
from pathlib import Path
from typing import TYPE_CHECKING, Any

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

project_root = Path(__file__).resolve().parents[1]
src_path = project_root / "src"
if str(src_path) not in sys.path:
    sys.path = [str(src_path), *sys.path]

from core.config.settings import config  # noqa: E402
from core.db.base import Base  # noqa: E402
from models import (  # noqa: F401,E402
    AgentChatMessage,
    AgentChatSession,
    AutomationJob,
    Group,
    GroupMember,
    InboxMessage,
    Llm,
    LlmFactory,
    Memory,
    Profile,
    ScheduleItem,
    ScheduleSubscription,
    Todo,
    TodoSource,
    UserAgent,
)

if TYPE_CHECKING:
    from sqlalchemy.engine import Connection

alembic_config = context.config

if alembic_config.config_file_name is not None:
    fileConfig(alembic_config.config_file_name)

target_metadata = Base.metadata


def _get_database_url() -> str:
    database_url = config.database_url
    if not database_url:
        raise RuntimeError(
            "DATABASE_URL is not configured. Set SOCIAL_INFRA__SUPABASE__DATABASE_URL."
        )
    return database_url


def _build_config() -> dict[str, Any]:
    section = alembic_config.get_section(alembic_config.config_ini_section) or {}
    return {**section, "sqlalchemy.url": _get_database_url()}


def run_migrations_offline() -> None:
    url = _get_database_url()
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        compare_type=True,
        compare_server_default=True,
        dialect_opts={"paramstyle": "named"},
    )

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


def _do_run_migrations(connection: "Connection" | Any) -> None:
    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_migrations_online() -> None:
    connectable = async_engine_from_config(
        _build_config(),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

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

    await connectable.dispose()


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