"""SQLAlchemy engine + Session 工厂。

FastAPI 路由通过 `Depends(get_db)` 拿到一个 request-scope 的 Session,
请求结束自动 close。
"""
from __future__ import annotations

import os
from collections.abc import Iterator

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker

from app.core.config import settings


def _ensure_sqlite_dir(url: str) -> None:
    """SQLite 文件路径如果在子目录,首启时自动 mkdir,避免 sqlalchemy 报 unable to open。"""
    prefix = "sqlite:///"
    if not url.startswith(prefix):
        return
    path = url[len(prefix):]
    dirname = os.path.dirname(path)
    if dirname:
        os.makedirs(dirname, exist_ok=True)


_ensure_sqlite_dir(settings.DATABASE_URL)

_is_sqlite = settings.DATABASE_URL.startswith("sqlite")

# SQLite 跨线程访问要 check_same_thread=False;PG/MySQL 不需要这个参数
_connect_args: dict = {}
if _is_sqlite:
    _connect_args["check_same_thread"] = False

_engine_kwargs: dict = {
    "connect_args": _connect_args,
    # echo 在 dev 下打 SQL,生产关掉
    "echo": settings.APP_DEBUG and not settings.is_prod,
    "future": True,
    "pool_pre_ping": True,
}
# SQLite 用单文件不需要池;PG/MySQL 必须显式池化 + recycle 防 idle 断连
if not _is_sqlite:
    _engine_kwargs.update(pool_size=10, max_overflow=20, pool_recycle=3600)

engine = create_engine(settings.DATABASE_URL, **_engine_kwargs)

SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False, expire_on_commit=False)


def get_db() -> Iterator[Session]:
    """FastAPI 依赖。请求开始建 session,请求结束自动 close。

    出异常时 SQLAlchemy 默认会标记 transaction 为 invalid,close 时自动 rollback。
    """
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
