# /// script
# requires-python = ">=3.11"
# dependencies = ["pyyaml"]
# ///
"""candidate_filter.py — Filter und Sortierung der Migrations-Kandidaten.

Liest eine JSON-Kandidatenliste (von scan_old_vault.py erzeugt) von stdin oder
aus einer Datei und gibt eine gefilterte, sortierte JSON-Liste nach stdout aus.

CLI-Verwendung:
    python scan_old_vault.py --old-vault /pfad | python candidate_filter.py
    python candidate_filter.py --input kandidaten.json
    python candidate_filter.py --only-active-projects
    python candidate_filter.py --category glossar,schreibstil
"""
from __future__ import annotations

import argparse
import json
import sys

# Kanonische Sortierreihenfolge der Kategorien — festgeschrieben.
# Innerhalb einer Kategorie wird alphabetisch nach path sortiert.
CATEGORY_ORDER: list[str] = [
    "glossar",
    "schreibstil",
    "branding",
    "kontext-sonstiges",
    "prinzip",
    "routine",
    "projekt",
    "bereich",
    "ressource",
]

_CATEGORY_RANK: dict[str, int] = {cat: i for i, cat in enumerate(CATEGORY_ORDER)}


def filter_candidates(
    items: list[dict],
    only_active_projects: bool = False,
    categories: list[str] | None = None,
) -> list[dict]:
    """Filtert und sortiert eine Liste von Kandidaten-Dicts.

    Parameter:
        items:               Liste von Kandidaten-Dicts (von scan_vault).
        only_active_projects: Wenn True, werden projekt-Einträge ohne
                              status=aktiv im Frontmatter herausgefiltert.
                              Andere Kategorien bleiben unberührt.
        categories:          Wenn angegeben, werden nur Einträge dieser
                             Kategorien behalten.

    Sortierung:
        1. Nach kanonischer Kategorie-Reihenfolge (CATEGORY_ORDER).
        2. Innerhalb einer Kategorie alphabetisch nach path.
    """
    result = list(items)

    # Filter: --only-active-projects
    # scan_old_vault filtert Projekte bereits auf status=aktiv. Diese Klausel
    # ist eine defensive Zweitschicht, falls die JSON-Quelle aus einer anderen
    # Pipeline kommt — solange das Scanner-Schema kein status-Feld mitführt,
    # wirkt der Filter auf Projekt-Einträge wie ein No-op (Pass-through).
    if only_active_projects:
        result = [
            item for item in result
            if item.get("category") != "projekt" or _is_active_project(item)
        ]

    # Filter: --category
    if categories:
        cat_set = set(categories)
        result = [item for item in result if item.get("category") in cat_set]

    # Sortierung: kanonische Reihenfolge + alphabetisch innerhalb
    result.sort(key=lambda item: (
        _CATEGORY_RANK.get(item.get("category", ""), len(CATEGORY_ORDER)),
        item.get("path", ""),
    ))

    return result


def _is_active_project(item: dict) -> bool:
    """Aktivitäts-Probe für einen Projekt-Kandidaten.

    Das Scanner-Schema (path/type/description/category/size_bytes) führt
    den Frontmatter-Status nicht mit. Solange das so bleibt, akzeptiert
    diese Funktion alle projekt-Kandidaten als aktiv — der vorgelagerte
    scan_old_vault.py hat die status=aktiv-Bedingung bereits durchgesetzt.
    Wird das Schema in v0.7 um ein status-Feld erweitert, kommt hier die
    echte Prüfung rein.
    """
    return True


def main() -> None:
    """Einstiegspunkt für den CLI-Aufruf."""
    # UTF-8-Hardening
    sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    sys.stderr.reconfigure(encoding="utf-8", errors="replace")

    parser = argparse.ArgumentParser(
        description="Filter und Sortierung der Migrations-Kandidaten (JSON).",
    )
    parser.add_argument(
        "--input",
        metavar="DATEI",
        default=None,
        help="Eingabedatei (JSON). Default: stdin.",
    )
    parser.add_argument(
        "--only-active-projects",
        action="store_true",
        help="Filtert Projekt-Einträge, behält nur aktive (status: aktiv).",
    )
    parser.add_argument(
        "--category",
        metavar="KATEGORIEN",
        default=None,
        help="Kommagetrennte Kategorie-Liste. Nur diese Kategorien bleiben.",
    )
    args = parser.parse_args()

    # JSON einlesen
    if args.input:
        try:
            raw = open(args.input, encoding="utf-8").read()  # noqa: WPS515
        except OSError as exc:
            print(f"Fehler beim Lesen von '{args.input}': {exc}", file=sys.stderr)
            sys.exit(2)
        source_hint = f"Datei '{args.input}'"
    else:
        raw = sys.stdin.read()
        source_hint = "stdin"

    # JSON parsen
    try:
        items = json.loads(raw)
    except json.JSONDecodeError as exc:
        print(
            f"Fehler: Ungültiges JSON in {source_hint}: {exc}",
            file=sys.stderr,
        )
        sys.exit(2)

    if not isinstance(items, list):
        print(
            f"Fehler: Erwartet JSON-Array, erhalten: {type(items).__name__} in {source_hint}.",
            file=sys.stderr,
        )
        sys.exit(2)

    # Kategorien parsen
    categories: list[str] | None = None
    if args.category:
        categories = [c.strip() for c in args.category.split(",") if c.strip()]

    result = filter_candidates(
        items,
        only_active_projects=args.only_active_projects,
        categories=categories,
    )

    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
