"""
Sequential migration runner.

Replays all migrations in order. All databases — fresh and existing —
go through the same path. No schema.sql fast-path.

- Scans versions/ for NNNN_*.py files and runs unapplied ones in order
- Each migration has an up(conn) function receiving an uncommitted connection
- All pending migrations share a single transaction (batch atomicity)
"""

import importlib
import os
import re
import sqlite3
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))

from dotenv import load_dotenv

load_dotenv()

VERSIONS_DIR = Path(__file__).parent / "versions"
VERSION_RE = re.compile(r"^(\d{4})_.+\.py$")

# Derived from the package path: …/src/<slug>/migrations/migrate.py
_PACKAGE = Path(__file__).parent.parent.name  # e.g. "myproject"


def _discover_versions():
    """Return sorted list of version file stems."""
    if not VERSIONS_DIR.is_dir():
        return []
    versions = []
    for f in sorted(VERSIONS_DIR.iterdir()):
        if VERSION_RE.match(f.name):
            versions.append(f.stem)
    return versions


def migrate(db_path=None):
    if db_path is None:
        db_path = os.getenv("DATABASE_PATH", "data/app.db")
    Path(db_path).parent.mkdir(parents=True, exist_ok=True)

    conn = sqlite3.connect(db_path)
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA foreign_keys=ON")

    # Ensure tracking table exists before anything else
    conn.execute("""
        CREATE TABLE IF NOT EXISTS _migrations (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT UNIQUE NOT NULL,
            applied_at TEXT NOT NULL DEFAULT (datetime('now'))
        )
    """)
    conn.commit()

    versions = _discover_versions()
    applied = {
        row[0]
        for row in conn.execute("SELECT name FROM _migrations").fetchall()
    }
    pending = [v for v in versions if v not in applied]

    if pending:
        for name in pending:
            print(f"  Applying {name}...")
            mod = importlib.import_module(
                f"{_PACKAGE}.migrations.versions.{name}"
            )
            mod.up(conn)
            conn.execute(
                "INSERT INTO _migrations (name) VALUES (?)", (name,)
            )
        conn.commit()
        print(f"✓ Applied {len(pending)} migration(s): {db_path}")
    else:
        print(f"✓ All migrations already applied: {db_path}")

    # Show tables (excluding internal sqlite/fts tables)
    cursor = conn.execute(
        "SELECT name FROM sqlite_master WHERE type='table'"
        " AND name NOT LIKE 'sqlite_%'"
        " ORDER BY name"
    )
    tables = [row[0] for row in cursor.fetchall()]
    print(f"  Tables: {', '.join(tables)}")

    conn.close()


if __name__ == "__main__":
    migrate()
