"""Unified migration runner for NEUROVAULT schema upgrades."""

from __future__ import annotations

import logging
import sqlite3
from typing import Callable

from neurovault.migrations.v01_to_v02 import migrate_v01_to_v02
from neurovault.migrations.v02_to_v03 import migrate_v02_to_v03

logger = logging.getLogger(__name__)

MIGRATIONS: dict[tuple[str, str], Callable[[str], bool]] = {
    ("0.1.0", "0.2.0"): migrate_v01_to_v02,
    ("0.2.0", "0.3.0"): migrate_v02_to_v03,
}


class MigrationRunner:
    """Run schema migrations from current to target version."""

    VERSION_ORDER = ["0.1.0", "0.2.0", "0.3.0"]

    def __init__(self, db_path: str):
        self._db_path = db_path

    def get_current_version(self) -> str:
        conn = sqlite3.connect(self._db_path)
        try:
            conn.execute("CREATE TABLE IF NOT EXISTS schema_info (key TEXT PRIMARY KEY, value TEXT)")
            row = conn.execute("SELECT value FROM schema_info WHERE key = 'version'").fetchone()
            return str(row[0]) if row and row[0] else "0.1.0"
        except Exception:
            return "0.1.0"
        finally:
            conn.close()

    def migrate_to(self, target_version: str = "0.3.0") -> bool:
        current = self.get_current_version()
        if current not in self.VERSION_ORDER or target_version not in self.VERSION_ORDER:
            logger.error("Unsupported migration path: %s -> %s", current, target_version)
            return False

        current_idx = self.VERSION_ORDER.index(current)
        target_idx = self.VERSION_ORDER.index(target_version)
        if current_idx >= target_idx:
            return True

        for idx in range(current_idx, target_idx):
            from_v = self.VERSION_ORDER[idx]
            to_v = self.VERSION_ORDER[idx + 1]
            migration = MIGRATIONS.get((from_v, to_v))
            if migration is None:
                logger.error("No migration registered: %s -> %s", from_v, to_v)
                return False

            logger.info("Running migration %s -> %s", from_v, to_v)
            ok = migration(self._db_path)
            if not ok:
                return False
            self._set_version(to_v)

        return True

    def _set_version(self, version: str) -> None:
        conn = sqlite3.connect(self._db_path)
        try:
            conn.execute("CREATE TABLE IF NOT EXISTS schema_info (key TEXT PRIMARY KEY, value TEXT)")
            conn.execute("INSERT OR REPLACE INTO schema_info (key, value) VALUES ('version', ?)", (version,))
            conn.commit()
        finally:
            conn.close()
