from collections.abc import AsyncGenerator
import os
from typing import Any, Dict

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlmodel import SQLModel
from . import settings as saas_settings

# CRITICAL FIX: Use settings.DATABASE_URL as single source of truth
# This avoids dual SQLite file confusion (fmatch.db vs foundrymatch.db)
DATABASE_URL = saas_settings.DATABASE_URL

if not DATABASE_URL:
    raise RuntimeError(
        "DATABASE_URL is not configured. Set the environment variable to a PostgreSQL DSN."
    )

# Transform sync URL to async URL based on database type
ALLOW_TEST_SQLITE = os.getenv("FMATCH_ALLOW_SQLITE_FOR_TESTS") == "1"

if DATABASE_URL.startswith("postgresql+asyncpg://"):
    ASYNC_DATABASE_URL = DATABASE_URL
elif DATABASE_URL.startswith("postgresql://"):
    # Convert sync PostgreSQL URL to async
    ASYNC_DATABASE_URL = DATABASE_URL.replace(
        "postgresql://", "postgresql+asyncpg://", 1
    )
elif DATABASE_URL.startswith("sqlite") and ALLOW_TEST_SQLITE:
    # Allow test harnesses to use in-memory SQLite when explicitly opted in.
    if DATABASE_URL.startswith("sqlite+aiosqlite://"):
        ASYNC_DATABASE_URL = DATABASE_URL
    else:
        ASYNC_DATABASE_URL = DATABASE_URL.replace("sqlite://", "sqlite+aiosqlite://", 1)
else:
    raise RuntimeError(
        f"Unsupported DATABASE_URL '{DATABASE_URL}'. Only PostgreSQL connections are supported."
    )


def _build_async_engine_kwargs(database_url: str) -> Dict[str, Any]:
    kwargs: Dict[str, Any] = {"echo": False, "future": True}
    if database_url.startswith("postgresql"):
        kwargs.update(
            {
                "pool_size": max(1, int(getattr(saas_settings, "DATABASE_POOL_SIZE", 20))),
                "max_overflow": max(
                    0, int(getattr(saas_settings, "DATABASE_MAX_OVERFLOW", 30))
                ),
                "pool_timeout": max(
                    1, int(getattr(saas_settings, "DATABASE_POOL_TIMEOUT", 5))
                ),
                "pool_pre_ping": bool(
                    getattr(saas_settings, "DATABASE_POOL_PRE_PING", True)
                ),
            }
        )
    return kwargs


engine = create_async_engine(ASYNC_DATABASE_URL, **_build_async_engine_kwargs(ASYNC_DATABASE_URL))

# Session factory with proper configuration
AsyncSessionLocal = async_sessionmaker(
    engine, expire_on_commit=False, class_=AsyncSession
)

# Backwards compatibility alias (legacy imports expect async_session_maker)
async_session_maker = AsyncSessionLocal


async def get_session() -> AsyncGenerator[AsyncSession, None]:
    """FastAPI dependency to yield an async database session."""
    async with AsyncSessionLocal() as session:
        yield session


# Base class for all our SQLModel models to inherit from
# This allows Alembic to find all tables easily.
Base = SQLModel
