from __future__ import annotations

from pathlib import Path
import sys

from sqlalchemy.exc import OperationalError, ProgrammingError
from sqlalchemy import text

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

from services.shared.db import engine
from services.shared.schema_migrations import (
    MIGRATIONS_DIR,
    applied_migration_versions,
    database_backend_name,
    ensure_schema_migrations_table,
    list_migration_files,
)


def _split_statements(sql: str) -> list[str]:
    chunks = []
    for part in sql.split(";"):
        stmt = part.strip()
        if stmt:
            chunks.append(stmt)
    return chunks


def _apply_file(path: Path) -> None:
    # Some checked-in SQL files may contain a UTF-8 BOM; accept them for both
    # local SQLite runs and Postgres migration jobs.
    statements = _split_statements(path.read_text(encoding="utf-8-sig"))
    with engine.begin() as conn:
        for stmt in statements:
            try:
                conn.execute(text(stmt))
            except (OperationalError, ProgrammingError) as exc:
                message = str(exc).lower()
                duplicate_markers = [
                    "duplicate column name",
                    "already exists",
                    "duplicate key value violates unique constraint",
                ]
                if any(marker in message for marker in duplicate_markers):
                    continue
                raise
        conn.execute(
            text("INSERT INTO schema_migrations(version, applied_at) VALUES (:v, CURRENT_TIMESTAMP)"),
            {"v": path.name},
        )


def main() -> None:
    files = list_migration_files()
    if not files:
        raise RuntimeError(f"No migration files found for dialect in {MIGRATIONS_DIR}")

    ensure_schema_migrations_table()
    applied = applied_migration_versions()

    applied_now = []
    for file_path in files:
        if file_path.name in applied:
            continue
        _apply_file(file_path)
        applied_now.append(file_path.name)

    print(f"Dialect: {database_backend_name()}")
    if applied_now:
        print("Applied migrations:")
        for m in applied_now:
            print(f"- {m}")
    else:
        print("No new migrations to apply")


if __name__ == "__main__":
    main()
