from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
TEMPLATES_DIR = PROJECT_ROOT / "templates"
STORAGE_DIR = PROJECT_ROOT / "storage"
FRONTEND_DIST = PROJECT_ROOT / "frontend" / "dist"
DB_PATH = STORAGE_DIR / "creator.db"
PROJECTS_DIR = PROJECT_ROOT / "projects"
UNI_DIR = PROJECT_ROOT / "uni"

MAX_CONCURRENT_GENERATIONS = 10

# Lesbarkeits-Gate: deterministischer Prüfer (kleines deutsches Komplexitäts-Modell,
# Skala 1–7). Zu schwere Sections gehen in die Lese-Prüfungs-Überarbeitung.
# Fehlen transformers/torch oder das Modell → Gate stumm aus.
LESBARKEIT_AKTIV = True
LESBARKEIT_MODELL = "MiriUll/distilbert-german-text-complexity"
# Anker auf der 1–7-Skala (TextComplexityDE): Leichte Sprache ~1,2; Wikipedia-Schnitt
# ~3,22; ab MOS > 4 gilt ein Satz als „echt komplex" (Vereinfachungs-Grenze des Papers).
LESBARKEIT_MAX = 3.5          # Section zu schwer, wenn der Satz-Schnitt darüber liegt
LESBARKEIT_HART = 4.0         # Einzelsatz ab hier „hart"
LESBARKEIT_HART_ANTEIL = 0.30  # … ODER wenn dieser Anteil der Sätze hart ist

# Deckel für gleichzeitige CLI-Agenten-Prozesse (über alle Generierungen hinweg).
# Eigene Spur für interaktive Aufrufe (Chat, Elemente), damit sie nicht hinter
# laufenden Writern in der Warteschlange hängen.
MAX_CONCURRENT_AGENTS = 10
MAX_CONCURRENT_INTERACTIVE = 4

# Grace-Fenster der Konsens-Races (Bausteine, Guide, OnePager): Nach dem ersten
# gültigen Ergebnis dürfen die übrigen Agenten noch so viele Sekunden fertig
# werden (Kill nur, wenn das Minimum schon steht).
KONSENS_GRACE = 300

# Recherche-Race: längeres Grace-Fenster. Recherche treibt die ganze Bausteine-Anzahl;
# bei langsamen Providern (z.B. MiniMax) sollen ALLE 5 Agenten fertig werden, nicht nur
# das Quorum von 3. Pro-Agent-Timeout (TIMEOUTS["recherche"]=1800s) deckelt echte Hänger.
RECHERCHE_GRACE = 900

# Cap der Klärungs- und Prüf-Loops: maximale Runden, bis alles entschieden sein
# muss. In der letzten Runde MUSS der Mapping-Agent jeden Eintrag entscheiden;
# Prüf-Loops lassen Rest-Beanstandungen danach stehen.
KONSENS_MAX_RUNDEN = 3

# Crawler-Sichtung (Content/Noise) — deterministischer Regel-Filter statt LLM.
# Match: Substring (klein) gegen URL UND Dateiname. Reihenfolge: keep > noise > min_chars > behalten.
# Sonderregeln einfach hier ergänzen.
CRAWL_KEEP_PATTERNS = ["learn-unit", "learn-course"]            # immer Content
CRAWL_NOISE_PATTERNS = [                                         # eindeutig themenfremd → raus
    "clubs", "events", "podcasts", "resources", "-u-",
    "academy", "pricing", "/plans", "career", "newsletter", "impressum", "login",
]
CRAWL_MIN_CHARS = 400                                            # zu wenig Text → raus

# Timeouts pro Agenten-Schritt: (Basis-Sekunden, Sekunden pro Baustein/Section).
# Gilt für alle Provider gleich — wer zu langsam ist, wird neu gestartet bzw. überholt.
TIMEOUTS = {
    "recherche":     (1800, 0),   # fix 30 min
    "recherche_mapping": (600, 3),  # n = vorgemergte Einträge
    "auswahl_mapping":   (600, 2),  # n = Rest-Einträge (Bausteine-Inventar)
    "ergaenzung":    (900, 0),   # Themenfeld-Ergänzung bei Projekten (Web-Recherche)
    "plan":          (300, 5),
    "plan_judge":    (600, 5),    # Judge liest bis zu 5 Gliederungen, n = Sections
    "inhalt":        (600, 90),   # Inhalte je Baustein im Chunk identifizieren (Websuche)
    "inhalt_check":  (300, 10),   # Inhalts-Prüfung je Baustein im Paket
    "subbaustein":       (900, 45),  # Subbausteine je Baustein im Chunk finden (Websuche)
    "subbaustein_check": (300, 15),  # Judge entscheidet strittige Subbausteine im Chunk
    "stufe":             (300, 10),  # Subbausteine einstufen je Chunk
    "stufe_check":       (300, 10),  # Judge entscheidet strittige Stufen im Chunk
    "relevanz":          (300, 10),  # Subbausteine relevant/rand je Chunk
    "relevanz_check":    (300, 10),  # Judge entscheidet strittige Relevanz im Chunk
    "frage_muster":      (300, 15),  # Frage-Muster je Baustein (Subbausteine × Typen)
    "frage_muster_check": (300, 10),  # Kritiker bereinigt die Muster-Tabelle je Baustein
    "writer":        (600, 120),  # pro Section im Chunk
    "lese_check":    (300, 10),   # pro Section im Paket
}

# Zweck je Format — fließt in den Gliederungs-Judge (was der Guide leisten soll).
FORMAT_ZWECK = {
    "Guide": "einen fokussierten Guide — alles Relevante ohne Randthemen",
    "FullGuide": "einen Komplett-Guide — das ganze Thema inkl. Randthemen",
    "Rest": "einen Ergänzungs-Guide — nur die Randthemen",
}

# Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden.
# Rollen: "quick" = Massenarbeit (Recherche, Einordnung),
#         "fast"  = Interaktion + Voten (Chat, Prüfung, Klärung, Elemente),
#         "judge" = Mapping-/Judge-/Prüf-Agenten — kalt (niedrige Temperature,
#                   ohne Thinking) für stabile Urteile; Claude/Lokal mappen auf "fast",
#         "guide" = große Generierung (Vorschläge, Writer).
DEFAULT_PROVIDER = "claude"
PROVIDERS = {
    "claude": {
        "cli": "claude",
        "guide": "claude-opus-4-8[1m]",
        "fast": "claude-sonnet-4-6",
        "judge": "claude-sonnet-4-6",  # CLI kennt keine Temperature
        "quick": "claude-sonnet-4-6",
        "env_key": None,  # Auth via CLAUDE_CODE_OAUTH_TOKEN oder ~/.claude
    },
    # "minimax-kalt/…" ist KEIN eigener Stack, nur ein opencode-Provider-Eintrag
    # (dev-ops/opencode.json) mit niedriger Temperature; M3 dort ohne Thinking.
    "minimax": {
        "cli": "opencode",
        "guide": "minimax/MiniMax-M3",
        "fast": "minimax-kalt/MiniMax-M2.7-highspeed",
        "judge": "minimax-kalt/MiniMax-M3",
        "quick": "minimax/MiniMax-M2.7-highspeed",
        "env_key": "MINIMAX_API_KEY",
    },
    "lokal": {
        "cli": "opencode",
        "guide": "ollama/qwen3.6:27b",
        "fast": "ollama/qwen3.5:9b",
        "judge": "ollama/qwen3.5:9b",
        "quick": "ollama/qwen3.5:9b",
        "env_key": None,
        "check_url": "http://localhost:11434/api/tags",  # Ollama erreichbar?
    },
}
