"""Auto-discover migration version files from the versions/{dialect}/ directory.

Version files are Python modules with a numeric prefix (e.g., ``0001_init.py``).
They are sorted lexicographically by filename — this is the execution order.

PostgreSQL migrations live in ``versions/postgres/``, Doris migrations live in
``versions/doris/``.  Each file exports the dialect-specific function:

* ``VERSION = "0001"`` — the version identifier (optional, derived from filename when absent)
* ``get_postgres_migrations() -> list[Migration]`` (postgres/ files)
* ``get_doris_migrations() -> list[Migration]`` (doris/ files)

Usage::

    from repo_core.migrations.discovery import discover_migrations

    # All PostgreSQL migrations from all version files, in order
    pg = discover_migrations("postgresql")

    # PostgreSQL migrations up to and including file 0002
    pg = discover_migrations("postgresql", up_to_file="0002")
"""

from __future__ import annotations

import importlib
from pathlib import Path
from repo_core.migrations.runner import Migration


def _dialect_subdir(dialect: str) -> str:
    """Return the versions subdirectory name for a given dialect."""
    if dialect == "doris":
        return "doris"
    return "postgres"


def _version_files(dialect: str) -> list[Path]:
    """Return all Python version files from versions/{dialect}/, sorted by filename."""
    versions_dir = Path(__file__).resolve().parent / "versions" / _dialect_subdir(dialect)
    if not versions_dir.is_dir():
        return []

    files: list[Path] = []
    for p in sorted(versions_dir.glob("*.py")):
        name = p.name
        if name.startswith("_") or name.startswith("__"):
            continue
        if not name[0].isdigit():
            continue
        files.append(p)
    return files


def _module_name(filepath: Path, dialect: str) -> str:
    """Convert a file path to a dotted module name for import."""
    # e.g., .../migrations/versions/postgres/0001_init.py → repo_core.migrations.versions.postgres.0001_init
    subdir = _dialect_subdir(dialect)
    return f"repo_core.migrations.versions.{subdir}.{filepath.stem}"


def _dialect_func(dialect: str) -> str:
    """Return the function name expected in version files for a given dialect."""
    if dialect == "doris":
        return "get_doris_migrations"
    return "get_postgres_migrations"


def discover_migrations(
    dialect: str,
    *,
    up_to_file: str | None = None,
) -> list[Migration]:
    """Discover and return ordered migrations for the given dialect.

    Args:
        dialect: ``"postgresql"`` or ``"doris"``.
        up_to_file: If set, only include migrations from version files whose
            numeric prefix is ≤ this value (lexicographically).  E.g., ``"0002"``
            includes files ``0001_init.py`` and ``0002_alter.py``.

    Returns:
        Flattened list of :class:`Migration` objects in execution order.
    """
    func_name = _dialect_func(dialect)
    all_migrations: list[Migration] = []

    for filepath in _version_files(dialect):
        # Extract the numeric prefix from filename (e.g., "0001" from "0001_init.py")
        file_prefix = filepath.stem.split("_", 1)[0]

        if up_to_file is not None and file_prefix > up_to_file:
            break

        mod = importlib.import_module(_module_name(filepath, dialect))
        func = getattr(mod, func_name, None)
        if func is None:
            continue

        for m in func():
            all_migrations.append(m)

    return all_migrations
