"""Remise à zéro de la base DATA de dev : drop du schéma public → alembic upgrade head → seed.

Commande destructrice, réservée au dev : refuse toute DATABASE_URL dont l'hôte n'est pas
localhost / 127.0.0.1 / ::1.

Usage : uv run python -m app.db_reset --org-id <id>
"""

import argparse
import asyncio
import sys
from pathlib import Path

from alembic import command
from alembic.config import Config
from alembic.script import ScriptDirectory
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine

from app import seed
from app.core.config import get_settings
from app.db.guard import assert_local

# Résolu depuis ce fichier, jamais depuis le cwd : `script_location = %(here)s/alembic` suit.
ALEMBIC_INI = Path(__file__).resolve().parents[1] / "alembic.ini"


def alembic_config() -> Config:
    return Config(str(ALEMBIC_INI))


async def drop_public_schema(url: str) -> None:
    # Le rôle seoinsight est propriétaire de la base : il peut recréer `public`.
    # `alembic_version` vit dans `public` : le CASCADE l'emporte, les migrations rejouent
    # donc bien depuis zéro.
    engine = create_async_engine(url)
    try:
        async with engine.begin() as conn:
            await conn.execute(text("DROP SCHEMA IF EXISTS public CASCADE"))
            await conn.execute(text("CREATE SCHEMA public"))
    finally:
        await engine.dispose()


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        prog="python -m app.db_reset",
        description="Vide la base DATA de dev, rejoue les migrations et lance le seed.",
    )
    parser.add_argument(
        "--org-id",
        required=True,
        help="identifiant de l'organisation « Dev » (ligne ORG_ID=… de `bun run db:seed`)",
    )
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv)
    url = str(get_settings().database_url)
    try:
        assert_local(url)
    except RuntimeError as exc:
        print(exc, file=sys.stderr)
        return 1
    # Les migrations sont chargées avant le drop : une configuration Alembic cassée doit
    # échouer pendant que la base est encore intacte.
    cfg = alembic_config()
    ScriptDirectory.from_config(cfg)
    # `alembic/env.py` appelle `asyncio.run()` : chaque étape async tourne dans sa propre boucle,
    # jamais sous une boucle déjà ouverte.
    asyncio.run(drop_public_schema(url))
    print("Base data vidée (schéma public recréé).")
    command.upgrade(cfg, "head")
    asyncio.run(seed.run(args.org_id))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
