from pydantic import BaseModel, Field
from typing import Literal

FormatType = Literal[
    "OnePager",
    "MiniGuide",
    "Guide",
    "ProGuide",
    "FullGuide",
]

ProviderType = Literal["claude", "minimax", "lokal"]

SourceType = Literal["thema", "projekt", "uni", "link"]


class GuideCreateRequest(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    format: FormatType
    instructions: str = Field(default="", max_length=2000)
    provider: ProviderType = "claude"


class TopicCreateRequest(BaseModel):
    name: str = Field(min_length=1, max_length=100)


class BausteineCreateRequest(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    instructions: str = Field(default="", max_length=2000)
    provider: ProviderType = "claude"
    source_type: SourceType = "thema"
    source_ort: str = Field(default="", max_length=2000)
    ab_phase: int | None = Field(default=None, ge=1, le=5)  # Re-Run ab grober Phase (1 Inventar … 5 Fragen); None = Resume/Fortsetzen ohne Löschen


class BausteineStep(BaseModel):
    label: str
    state: Literal["done", "active", "pending"]


class BausteineStatusResponse(BaseModel):
    ready: bool
    generating: bool
    progress: str | None = None
    error: str | None = None
    partial: bool = False
    steps: list[BausteineStep] = []


class ProjectResponse(BaseModel):
    name: str


class FolderResponse(BaseModel):
    name: str
    ort: str  # relativer Pfad ab Repo-Root (z.B. "projects/foo")


class BausteineQuelleUpdate(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    type: SourceType = "thema"
    ort: str = Field(default="", max_length=2000)
    spec: str = Field(default="", max_length=2000)


class BausteineQuelleResponse(BaseModel):
    type: SourceType
    ort: str
    spec: str


class SubbausteinInfo(BaseModel):
    titel: str
    stufe: Literal["einfach", "mittel", "schwer"]
    relevanz: Literal["relevant", "rand"] | None = None


class BausteinUebersicht(BaseModel):
    num: int
    titel: str
    beschreibung: str = ""
    subbausteine: list[SubbausteinInfo] = []


class ProviderInfo(BaseModel):
    id: str
    available: bool


class GuideResponse(BaseModel):
    id: str
    topic: str
    format: str
    status: str
    progress: str | None = None
    step: int | None = None
    error_msg: str | None = None
    created_at: str
    updated_at: str


class ChatMessage(BaseModel):
    role: Literal["user", "assistant"]
    content: str = Field(min_length=1, max_length=8000)


class GuideChatRequest(BaseModel):
    section: str = Field(default="", max_length=20000)
    outline: str = Field(default="", max_length=8000)
    messages: list[ChatMessage] = Field(min_length=1)
    provider: ProviderType = "claude"


class GuideChatResponse(BaseModel):
    reply: str


class ElementResponse(BaseModel):
    id: str
    topic: str
    title: str
    description: str = ""
    examples: list[str] = []
    hints: list[str] = []
    created_at: str
    updated_at: str


class ElementCreateRequest(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    hint: str = Field(default="", max_length=500)
    provider: ProviderType = "claude"


class ElementUpdateRequest(BaseModel):
    title: str | None = Field(default=None, max_length=200)
    description: str | None = None
    examples: list[str] | None = None
    hints: list[str] | None = None


class ElementCheckRequest(BaseModel):
    provider: ProviderType = "claude"


class ElementSuggestion(BaseModel):
    text: str
    target: Literal["description", "examples", "hints"]
    content: str


class ElementCheckResponse(BaseModel):
    suggestions: list[ElementSuggestion]


class ElementStyleChange(BaseModel):
    text: str
    action: Literal["entfernen", "anpassen", "hinzufuegen"]
    target: Literal["title", "description", "examples", "hints"]
    index: int | None = None
    content: str = ""


class ElementStyleResponse(BaseModel):
    changes: list[ElementStyleChange]


class ElementChatRequest(BaseModel):
    messages: list[ChatMessage] = Field(min_length=1)
    provider: ProviderType = "claude"


class ElementChatResponse(BaseModel):
    reply: str
    changes: list[ElementStyleChange] = []


class ElementRefineRequest(BaseModel):
    suggestion: ElementStyleChange
    instruction: str = Field(min_length=1, max_length=2000)
    provider: ProviderType = "claude"


class ElementRefineResponse(BaseModel):
    change: ElementStyleChange


class ProgressUpdate(BaseModel):
    chapter: str = Field(min_length=1, max_length=100)
    done: bool


class ProgressResponse(BaseModel):
    chapters: list[str]


# --- Baustein-Lernen ---

class BausteinChatRequest(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    baustein: str = Field(min_length=1, max_length=200)
    section: str = Field(default="", max_length=20000)         # ausführliche Fassung
    section_kompakt: str = Field(default="", max_length=20000)  # kompakte Fassung (Merksätze)
    messages: list[ChatMessage] = Field(min_length=1)
    provider: ProviderType = "claude"


class BausteinChatResponse(BaseModel):
    reply: str


class BausteinPruefungRequest(BaseModel):
    topic: str = Field(min_length=1, max_length=100)
    baustein: str = Field(min_length=1, max_length=200)
    section: str = Field(default="", max_length=20000)         # ausführliche Fassung
    section_kompakt: str = Field(default="", max_length=20000)  # kompakte Fassung (Merksätze)
    aktion: Literal[
        "frage", "diskussion", "antwort", "antwort_pruefen",
        "quiz_frage", "quiz_antwort", "lueck_frage", "lueck_antwort",
    ] = "frage"
    frage: str = Field(default="", max_length=2000)  # aktuell geprüfte Frage (für diskussion/antwort); Anker der Basis
    auswahl: list[int] = []  # Quiz/Lückentext-Auswahl: vom Lerner gewählte Options-Indizes
    korrekt: list[int] = []  # Quiz/Lückentext-Auswahl: korrekte Indizes (Client hält sie aus der Generierung)
    loesung: str = Field(default="", max_length=500)  # Lückentext frei: erwarteter Begriff
    alternativen: list[str] = []  # Lückentext frei: akzeptierte Synonyme
    eingabe: str = Field(default="", max_length=500)  # Lückentext frei: getippter Begriff
    schwer: bool = False  # Variante: leicht (+1/−1) vs schwer (+3/−1)
    letzte_bewertung: str = Field(default="", max_length=2000)  # Feedback der letzten Bewertung (Kontext für diskussion)
    vermeide: list[str] = []  # schon gestellte + vorgemerkte Fragen — sinngemäß nicht wiederholen
    nachgefragt: bool = False  # für diese Frage wurde nachgefragt → Gewinn auf +1 gedeckelt
    begruendung: str = Field(default="", max_length=2000)  # „Gründlich prüfen": warum mit der Bewertung unzufrieden
    muster: str = Field(default="", max_length=2000)  # gezogenes Frage-Muster (Saat); leer → Live-Generierung (Fallback)
    # Basis wird serverseitig je Frage geführt (offene_frage-Anker) — nicht mehr vom Client.
    cap: int = Field(default=6, ge=6, le=30)  # Score-Deckel = Max des höchsten erstellten Formats (6/12/18/30)
    messages: list[ChatMessage] = []  # Dialog bisher; leer = erste Frage
    provider: ProviderType = "claude"
    gruendlich: bool = False  # „Gründlich prüfen": Bewertung mit starkem Modell (role guide)


class QuizOption(BaseModel):
    text: str
    korrekt: bool


class BausteinPruefungResponse(BaseModel):
    frage: str | None = None
    reply: str | None = None
    feedback: str | None = None
    punkte: int | None = None  # Punkt-Delta dieser Antwort (−2 … +3); schnell = voraussichtlich
    bewertung: Literal["gut", "neutral", "schlecht"] | None = None  # aus Vorzeichen, fürs Einfärben
    optionen: list[QuizOption] | None = None  # Quiz: 4 Optionen + Korrekt-Flags
    satz: str | None = None  # Lückentext: Satz mit Lücke (___)
    loesung: str | None = None  # Lückentext: erwarteter Begriff
    alternativen: list[str] | None = None  # Lückentext: akzeptierte Synonyme
    gute_antworten: int
    absolviert: bool
    verstanden: bool = False
    gemeistert: bool = False


class BausteinLernstand(BaseModel):
    gute_antworten: int
    streak: int = 0
    absolviert: bool
    verstanden: bool
    gemeistert: bool


class BausteinLernstandResponse(BaseModel):
    bausteine: dict[str, BausteinLernstand]
