"""
Управление SQLAlchemy движком и сессиями.
"""
from pathlib import Path
from typing import AsyncGenerator

from sqlalchemy.ext.asyncio import (
    create_async_engine,
    async_sessionmaker,
    AsyncSession,
    AsyncEngine
)

from configs import settings
from middleware.loggers import logger
from .models import Base

__all__ = ("Database", "get_db")


class Database:
    """
    Менеджер SQLAlchemy базы данных.

    Attributes:
        engine: Async движок SQLAlchemy
        session_factory: Фабрика сессий
    """

    def __init__(self, db_path: str = settings.DATABASE_PATH):
        """
        Args:
            db_path: Путь к SQLite файлу
        """
        # Создаём директорию если не существует
        db_file = Path(db_path)
        db_file.parent.mkdir(parents=True, exist_ok=True)

        # SQLite URL для async
        db_url = f"sqlite+aiosqlite:///{db_path}"

        # Создаём async движок
        self.engine: AsyncEngine = create_async_engine(
            db_url,
            echo=False,  # Логирование SQL запросов (False для прода)
            future=True,
            pool_pre_ping=True,  # Проверка соединения
        )

        # Фабрика сессий
        self.session_factory = async_sessionmaker(
            self.engine,
            class_=AsyncSession,
            expire_on_commit=False,
        )

        logger.info(
            f"SQLAlchemy инициализирован: {db_path}",
            log_type="DATABASE"
        )

    async def init(self) -> None:
        """Создаёт все таблицы в БД"""
        try:
            async with self.engine.begin() as conn:
                await conn.run_sync(Base.metadata.create_all)

            logger.info(
                "Таблицы базы данных созданы",
                log_type="DATABASE"
            )
        except Exception as e:
            logger.error(
                f"Ошибка создания таблиц: {e}",
                log_type="DATABASE"
            )
            raise

    async def close(self) -> None:
        """Закрывает соединения с БД"""
        await self.engine.dispose()
        logger.info("База данных закрыта", log_type="DATABASE")

    def get_session(self) -> AsyncGenerator[AsyncSession, None]:
        """
        Создаёт новую сессию (контекстный менеджер).

        Usage:
            async with db.get_session() as session:
                result = await session.execute(select(BanWord))
                words = result.scalars().all()

        Yields:
            AsyncSession: Сессия для работы с БД
        """
        return self.session_factory()


# Глобальный экземпляр
_db_instance: Database | None = None


def get_db(db_path: str = settings.DATABASE_PATH) -> Database:
    """
    Возвращает глобальный экземпляр Database (Singleton).

    Args:
        db_path: Путь к БД (используется только при первом вызове)

    Returns:
        Database: Экземпляр базы данных
    """
    global _db_instance
    if _db_instance is None:
        _db_instance = Database(db_path)
    return _db_instance
