"""Unified async database manager."""

from __future__ import annotations

import logging
from pathlib import Path

import aiosqlite
import asyncpg

from bot.config import DATABASE_URL, DB_PATH
from bot.infra.db.adapters import current_database_backend


logger = logging.getLogger(__name__)


class DatabaseManager:
    def __init__(self, path: str) -> None:
        self.path = path
        self._conn: aiosqlite.Connection | None = None
        self._pool: asyncpg.Pool | None = None

    async def connect(self) -> None:
        backend = current_database_backend()

        if backend == "postgresql":
            if self._pool:
                return

            self._pool = await asyncpg.create_pool(DATABASE_URL, min_size=1, max_size=10)

            logger.info("PostgreSQL pool connected")
            return

        if self._conn:
            return

        Path(self.path).parent.mkdir(parents=True, exist_ok=True)

        self._conn = await aiosqlite.connect(self.path)
        self._conn.row_factory = aiosqlite.Row

        await self._conn.execute("PRAGMA journal_mode=WAL")
        await self._conn.execute("PRAGMA foreign_keys=ON")
        await self._conn.commit()

        logger.info("Database connected: %s", self.path)

    async def close(self) -> None:
        if self._pool:
            await self._pool.close()
            self._pool = None

            logger.info("PostgreSQL pool closed")

        if not self._conn:
            return

        await self._conn.close()
        self._conn = None

        logger.info("Database connection closed")

    async def execute(self, sql: str, params: tuple = ()):
        if self._pool:
            async with self._pool.acquire() as conn:
                return await conn.execute(sql, *params)

        conn = await self.connection()
        cursor = await conn.execute(sql, params)
        await conn.commit()
        return cursor

    async def fetchone(self, sql: str, params: tuple = ()):
        if self._pool:
            async with self._pool.acquire() as conn:
                return await conn.fetchrow(sql, *params)

        conn = await self.connection()
        cursor = await conn.execute(sql, params)
        return await cursor.fetchone()

    async def fetchall(self, sql: str, params: tuple = ()):
        if self._pool:
            async with self._pool.acquire() as conn:
                return await conn.fetch(sql, *params)

        conn = await self.connection()
        cursor = await conn.execute(sql, params)
        return await cursor.fetchall()

    async def connection(self) -> aiosqlite.Connection:
        if not self._conn:
            await self.connect()

        return self._conn


db_manager = DatabaseManager(DB_PATH)
