"""
Автоматические миграции БД для max_bot.

При старте приложения:
  1. Создаёт таблицу _applied_migrations (если не существует)
  2. Проверяет какие SQL-файлы уже применены
  3. Применяет новые миграции по порядку

ВАЖНО: asyncpg не поддерживает несколько SQL-команд в одном text().
Поэтому каждый SQL-файл разбивается на отдельные команды по ';' .
"""
import os
import re
import logging
from sqlalchemy import text
from app.database import engine

logger = logging.getLogger(__name__)

MIGRATIONS_DIR = os.path.join(os.path.dirname(__file__), "migrations")


def _split_sql(sql: str) -> list:
    """Разбивает SQL-файл на отдельные команды, пропуская комментарии и пустые строки."""
    statements = []
    for stmt in sql.split(";"):
        # Убираем комментарии (-- ...) и пустые строки
        lines = []
        for line in stmt.split("\n"):
            stripped = line.strip()
            if stripped.startswith("--"):
                continue
            if stripped:
                lines.append(stripped)
        clean = " ".join(lines)
        if clean:
            statements.append(clean)
    return statements


async def run_migrations():
    """Запуск всех неприменённых миграций из директории migrations/."""
    async with engine.begin() as conn:
        # Создаём таблицу для отслеживания миграций
        await conn.execute(text("""
            CREATE TABLE IF NOT EXISTS _applied_migrations (
                id SERIAL PRIMARY KEY,
                filename VARCHAR(255) UNIQUE NOT NULL,
                applied_at TIMESTAMP DEFAULT NOW()
            )
        """))

        # Получаем список уже применённых миграций
        result = await conn.execute(text("SELECT filename FROM _applied_migrations"))
        applied = {row[0] for row in result.all()}

        # Сканируем директорию миграций
        if not os.path.isdir(MIGRATIONS_DIR):
            logger.info("Директория migrations/ не найдена, пропускаем")
            return

        sql_files = sorted(f for f in os.listdir(MIGRATIONS_DIR) if f.endswith(".sql"))

        for filename in sql_files:
            if filename in applied:
                continue

            filepath = os.path.join(MIGRATIONS_DIR, filename)
            with open(filepath, "r", encoding="utf-8") as f:
                sql = f.read()

            statements = _split_sql(sql)
            logger.info(f"Применение миграции: {filename} ({len(statements)} команд)")

            try:
                for stmt in statements:
                    await conn.execute(text(stmt))
                await conn.execute(
                    text("INSERT INTO _applied_migrations (filename) VALUES (:fn)"),
                    {"fn": filename}
                )
                logger.info(f"Миграция применена: {filename}")
            except Exception as e:
                logger.warning(f"Миграция {filename} уже применена или ошибка: {e}")
