"""CLI des Planers (Phase 1, kein Server):

  python -m backend scan <pfad>     Erst-Scan eines Projekt-Repos
  python -m backend rescan <pfad>   Re-Scan über git-Diff gegen die Anker-Stände
  python -m backend status          Karten-Stände aller bekannten Läufe
"""
import argparse
import asyncio
import logging
import os
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))  # `python -m backend` von der Wurzel

import agents  # noqa: E402
import database as db
import scan_dienst

log = logging.getLogger("planer")


def _abbruch(meldung: str) -> "NoReturn":  # noqa: F821
    print(f"ABBRUCH: {meldung}", file=sys.stderr)
    sys.exit(1)


def _vorflug(wurzel: Path) -> str:
    try:
        return scan_dienst.vorflug(wurzel)
    except scan_dienst.VorflugFehler as e:
        _abbruch(str(e))


def _fortschritt(text: str) -> None:
    print(f"  {text}", flush=True)


def _bericht(ergebnis: dict) -> None:
    print(f"Status: {ergebnis['status']}")
    if ergebnis.get("infra_error"):
        print(f"  Infra: {ergebnis['infra_error']}")
    for pfad in ergebnis.get("geschrieben", []):
        print(f"  geschrieben: .planer/{pfad}")
    for card in ergebnis.get("dead", []):
        print(f"  DEAD: {card} (requeue über erneuten Lauf oder DB)")
    if ergebnis["status"] == "ok":
        print("Artefakte aktualisiert — jetzt committen (Code + .planer/ atomar).")


async def _scan(wurzel: Path, fortsetzen: bool = False) -> int:
    stand = _vorflug(wurzel)
    await db.init_db()
    agents.on_event = db.add_event
    import scan_board
    ergebnis = await scan_board.run_scan(wurzel, wurzel.name, stand, set_p=_fortschritt,
                                         fortsetzen=fortsetzen)
    _bericht(ergebnis)
    return 0 if ergebnis["status"] == "ok" else 1


async def _rescan(wurzel: Path) -> int:
    stand_neu = _vorflug(wurzel)
    await db.init_db()
    agents.on_event = db.add_event
    try:
        ergebnis = await scan_dienst.rescan_lauf(wurzel, wurzel.name, stand_neu,
                                                 set_p=_fortschritt)
    except scan_dienst.VorflugFehler as e:
        _abbruch(str(e))
    if ergebnis["status"] == "unveraendert":
        print("Keine Änderungen seit dem letzten Scan — nichts zu tun.")
        return 0
    _bericht(ergebnis)
    return 0 if ergebnis["status"] == "ok" else 1


async def _status() -> None:
    await db.init_db()
    verbindung = await db.get_db()
    cursor = await verbindung.execute("SELECT DISTINCT topic FROM kanban_cards ORDER BY topic")
    topics = [r[0] for r in await cursor.fetchall()]
    if not topics:
        print("Keine Läufe in der Planer-DB.")
        return
    for topic in topics:
        counts = await db.kanban_stage_counts(topic)
        dead = await db.kanban_dead(topic)
        print(f"{topic}: " + ", ".join(f"{s}={n}" for b in counts.values() for s, n in b.items())
              + (f" — DEAD: {[c['card_id'] for c in dead]}" if dead else ""))


def main() -> None:
    logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
    # Hänger-Diagnose (offener Befund: Prozess lebt nach Board-Ende weiter):
    # `kill -USR1 <pid>` schreibt alle Python-Stacks nach stderr.
    import faulthandler
    import signal as _signal
    faulthandler.register(_signal.SIGUSR1)
    parser = argparse.ArgumentParser(prog="planer")
    sub = parser.add_subparsers(dest="kommando", required=True)
    for name in ("scan", "rescan"):
        p = sub.add_parser(name)
        p.add_argument("pfad", type=Path)
        if name == "scan":
            p.add_argument("--fortsetzen", action="store_true",
                           help="abgebrochenen Lauf fortsetzen (nur tote Chunks neu)")
    sub.add_parser("status")
    args = parser.parse_args()
    if args.kommando == "scan":
        sys.exit(asyncio.run(_scan(args.pfad.resolve(), fortsetzen=args.fortsetzen)))
    elif args.kommando == "rescan":
        sys.exit(asyncio.run(_rescan(args.pfad.resolve())))
    else:
        asyncio.run(_status())


if __name__ == "__main__":
    main()
