"""Lernschulden-Regeln: Progression und Deckel für offene Guides — die EINZIGE Quelle.

Regeln (nur Neu-Erstellungen; Themen + Bausteine unbegrenzt):
- Format „Guide": höchstens 3 erstellte, nicht absolvierte Guides
- Keine Progression/Vorstufe mehr (nur ein Guide-Format).
- Absolviert: ALLE Bausteine (Section-Titel) des neuesten fertigen Guides haben
  eine bestandene Prüfung. Rest ist read-only (kein Fortschritt, keine Prüfung).
Alle Funktionen arbeiten auf einmal geladenen Daten (lade_lernstand) — keine
Query-Schleifen mehr pro Guide.
"""

import json

from database import list_baustein_levels_all, list_guides, list_progress_all
from guide import guide_slot_dateien
from paths import bausteine_path, guide_content_path
from textkit import _norm_titel

MAX_OFFENE_GUIDES = 3
# Nur noch EIN Format „Guide" (alle relevanten Bausteine, Prüfung 0–30). Keine Progression,
# keine Vorstufe → der Guide ist immer freischaltbar. „Rest"/FullGuide separat.
VORSTUFE: dict[str, str] = {}
FREISCHALT_LEVEL: dict[str, str] = {}
FORMATE = ("Guide",)

# Geforderter Score je Freischalt-Niveau — nur für die Sperr-Meldung.
_LEVEL_WORT = {
    "absolviert": "absolvieren (alle Bausteine auf 6)",
    "verstanden": "verstehen (alle Bausteine auf 12)",
    "gemeistert": "meistern (alle Bausteine auf 18)",
}


async def lade_lernstand() -> tuple[list[dict], dict[str, set[str]], dict[str, dict[str, set[str]]]]:
    """Guides + Kapitel-Fortschritt + Bausteine je Meilenstein.

    levels: {"absolviert"/"verstanden"/"gemeistert": {topic → normalisierte Titel}}.
    """
    roh = await list_baustein_levels_all()
    levels = {
        stufe: {topic: {_norm_titel(b) for b in titel} for topic, titel in pro_topic.items()}
        for stufe, pro_topic in roh.items()
    }
    return await list_guides(), await list_progress_all(), levels


def _content_json(topic: str, fmt: str) -> dict | None:
    path = guide_content_path(topic, fmt)
    if not path.exists():
        return None
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except ValueError:
        return None




def _section_titel(topic: str, fmt: str) -> set[str] | None:
    """Normalisierte Baustein-Titel (Sections) aus dem Guide-Content."""
    content = _content_json(topic, fmt)
    if content is None:
        return None
    return {
        _norm_titel(s.get("title", ""))
        for ch in content.get("chapters", [])
        for s in ch.get("sections", [])
    }


def _neueste_done(guides: list[dict], fmt: str) -> dict[str, dict]:
    """Pro Thema der neueste fertige Guide dieses Formats."""
    neueste: dict[str, dict] = {}
    for g in guides:
        if g["format"] == fmt and g["status"] == "done":
            if g["topic"] not in neueste or g["created_at"] > neueste[g["topic"]]["created_at"]:
                neueste[g["topic"]] = g
    return neueste


def _guide_alle(g: dict, progress: dict[str, set[str]], levelset: dict[str, set[str]]) -> bool:
    """Sind ALLE Bausteine des Guides auf dem geforderten Niveau?"""
    sections = _section_titel(g["topic"], g["format"])
    return bool(sections) and sections <= levelset.get(g["topic"], set())


def ist_level(topic: str, fmt: str, guides: list[dict], progress: dict[str, set[str]], levelset: dict[str, set[str]]) -> bool:
    """Neuester fertiger Guide (Thema+Format): alle Bausteine auf dem Niveau von levelset?"""
    g = _neueste_done(guides, fmt).get(topic)
    return g is not None and _guide_alle(g, progress, levelset)


def ist_absolviert(topic: str, fmt: str, guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> bool:
    """Alle Bausteine des neuesten fertigen Guides absolviert (≥3)?"""
    return ist_level(topic, fmt, guides, progress, levels["absolviert"])


def thema_abgeschlossen(topic: str, guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> bool:
    """Thema fertig: neuester fertiger Guide, alle Bausteine gemeistert (18)?"""
    return ist_level(topic, "Guide", guides, progress, levels["gemeistert"])


def formate_stats(guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> dict:
    """Pro Format erstellt/absolviert — pro Thema zählt nur der neueste fertige Guide."""
    formate = {}
    for fmt in FORMATE:
        neueste = _neueste_done(guides, fmt)
        absolviert = sum(1 for g in neueste.values() if _guide_alle(g, progress, levels["absolviert"]))
        formate[fmt] = {"erstellt": len(neueste), "absolviert": absolviert}
    return formate


def guide_lock(topic: str, fmt: str, guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> str | None:
    """Grund, warum ein Neu-Start für Thema+Format gesperrt ist — None = erlaubt.

    Exakt die Regeln aus POST /guides: Bausteine nötig, kein Duplikat-Start,
    Lernschulden nur für echte Neu-Erstellungen (Resume/Regenerieren frei).
    """
    if not bausteine_path(topic).exists():
        return "Erst Bausteine erstellen"
    for g in guides:
        if g["topic"] == topic and g["format"] == fmt and g["status"] in ("queued", "generating"):
            return "Generierung läuft bereits"
    content = guide_content_path(topic, fmt)
    if not content.exists() and not guide_slot_dateien(content):
        vorstufe = VORSTUFE.get(fmt)
        if vorstufe:
            stufe = FREISCHALT_LEVEL[fmt]  # absolviert=10 · verstanden=20 · gemeistert=30
            if not ist_level(topic, vorstufe, guides, progress, levels[stufe]):
                return f"Erst den {vorstufe} dieses Themas {_LEVEL_WORT[stufe]}"
        stat = formate_stats(guides, progress, levels).get(fmt, {"erstellt": 0, "absolviert": 0})
        offen = stat["erstellt"] - stat["absolviert"]
        if offen >= MAX_OFFENE_GUIDES:
            return f"Erst {fmt}s absolvieren — maximal {MAX_OFFENE_GUIDES} offene erlaubt ({offen} offen)"
    return None
