use super::AnalysisInput;

/// System prompt for the consolidation LLM.
/// Temperature 0 is set on the request; the prompt enforces "no interpretation".
///
/// Sandbox-validated against case c414cf52 (3 runs each, fair pipeline with
/// pre- and post-LLM gazetteer pass against the current vocab):
/// - eliminates two hallucination classes the previous prompt produced —
///   unmarked "Hypotonie" when the dictation said "Hypertonie" (0/3 vs 2/3),
///   and inventing a unit ("35 ng/l") for a dictated value without unit
///   (0/3 vs 2/3)
/// - keeps Latin terms intact ("Punctum Maximum", "Apex Cordis", "Axilla"
///   in 3/3 vs 2/3)
/// - relies on the gazetteer for drug-name correction (Enoxaparin etc.) —
///   the prompt no longer needs a separate "AKTIVE KORREKTUR" hammer-block
///   because the gazetteer's pre-LLM pass repairs the typical typos before
///   the LLM ever sees them
/// - block layout: AUFGABE / QUELLE / KORREKTUR-POLITIK / TREUE / CHRONOLOGIE
///   / DOSIERUNGSSCHEMA / MARKIERUNGEN — each rule appears exactly once
pub const SYSTEM_PROMPT: &str = r#"Du bist ein medizinischer Assistent.

AUFGABE: Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden, deutschen Fließtext zusammen — bereinigen und strukturieren, keine Diagnose, keine Arztbrief-Struktur, keine Einleitung, kein Abschlusssatz, nur der konsolidierte Text. Mehrere Absätze erlaubt. KEINE Inline-Sektionsmarker (kein "Status:", "Diagnostik:", "Therapie:", "Plan:"), KEINE Markdown-Headings, KEINE Aufzählungspunkte.

QUELLE: Das Diktat wurde automatisch transkribiert und enthält typische ASR-Fehler — phonetisch ähnliche Verwechslungen und zerschnittene Komposita (z.B. "Spolade" statt "Schokolade", "posbrandial" statt "postprandial", "in Faust" statt "infaust").

KORREKTUR-POLITIK:
- Bekannte Wirkstoffnamen, etablierte medizinische Akronyme und Standard-Termini bei eindeutigem ASR-Fehler aktiv und unmarkiert korrigieren.
- Bei Unsicherheit: Original behalten und mit ==...== markieren statt zu raten. KEINE medizinisch klingenden Komposita aus phonetischer Nähe konstruieren.

TREUE ZUM DIKTAT (höchste Priorität — vor allen anderen Regeln):
- Anatomische Lokalisationen, Werte mit Einheiten, Wirkstoffnamen, Dosierungen und genannte Befunde NIEMALS umformulieren, eindampfen oder weglassen. Wörtlich übernehmen.
- KEINE neuen Tatsachen oder medizinischen Interpretationen hinzufügen, auch nicht naheliegende.
- Werte mit Einheiten zusammenhalten ("35 ng/l", nicht nur "35"). Fehlt die Einheit im Diktat: Zahl markieren.

CHRONOLOGIE:
- Diktat-Reihenfolge erhalten — Befunde aus späteren Aufnahmen nicht in die Anamnese verschieben, auch wenn sie thematisch verwandt wirken.
- Bei widersprüchlichen Aussagen über mehrere Aufnahmen die chronologisch letzte übernehmen, die frühere weglassen oder als ==text== markieren. KEINE Verlaufsgeschichte konstruieren (NICHT "die im weiteren Verlauf als X beurteilt wird"). Wenn eine frühere Aufnahme einen offensichtlichen ASR-Fehler enthält und alle späteren die korrigierte Form zeigen: die spätere als korrekt nehmen, früheren Fehler nicht erwähnen.

DOSIERUNGSSCHEMA: 3–4 kleine Zahlen im Medikationskontext sind morgens-mittags-abends(-nachts). Schreibe kompakt: "eins null zwei" → "1-0-2", "eins null zwei null" → "1-0-2-0". Nur bei klarem Medikationskontext anwenden, sonst Original behalten und markieren.

MARKIERUNGEN: ==text== signalisiert dem Arzt "bitte prüfen". Sparsam einsetzen — eindeutig korrigierte Wirkstoffe und klar gesprochene Fachbegriffe bleiben unmarkiert. Keine anderen Annotations-Formen ("(unsicher)", "[TODO]" o.ä.) verwenden."#;

/// Render the user-content portion of the chat request from the persisted
/// JSON input. Recordings with blank text are skipped — they carry no signal
/// for the LLM and only add noise. Chronological order is taken as given;
/// callers must sort `recordings` before passing in (the handler does).
pub fn render_prompt(input: &AnalysisInput) -> String {
    let mut out = String::new();
    let mut first = true;
    for r in &input.recordings {
        if r.text.trim().is_empty() {
            continue;
        }
        if !first {
            out.push_str("\n\n---\n\n");
        }
        first = false;
        out.push_str("## ");
        out.push_str(&r.recorded_at);
        out.push_str("\n\n");
        out.push_str(r.text.trim());
    }
    out
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::analyze::RecordingInput;

    fn mk(input: Vec<(&str, &str)>) -> AnalysisInput {
        AnalysisInput {
            last_recording_mtime: "2026-04-15T10:47:00Z".into(),
            recordings: input
                .into_iter()
                .map(|(ts, text)| RecordingInput {
                    recorded_at: ts.into(),
                    text: text.into(),
                })
                .collect(),
        }
    }

    #[test]
    fn renders_single_recording() {
        let out = render_prompt(&mk(vec![(
            "2026-04-15T10:32:00Z",
            "Patient klagt über Knie.",
        )]));
        assert_eq!(out, "## 2026-04-15T10:32:00Z\n\nPatient klagt über Knie.");
    }

    #[test]
    fn renders_multiple_with_separator() {
        let out = render_prompt(&mk(vec![
            ("2026-04-15T10:32:00Z", "Erste Aufnahme."),
            ("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
        ]));
        assert!(out.contains("\n\n---\n\n"));
        assert!(out.starts_with("## 2026-04-15T10:32:00Z"));
        assert!(out.contains("## 2026-04-15T10:38:15Z"));
    }

    #[test]
    fn skips_blank_recordings() {
        let out = render_prompt(&mk(vec![
            ("2026-04-15T10:32:00Z", "Nur Inhalt."),
            ("2026-04-15T10:33:00Z", "   "),
            ("2026-04-15T10:34:00Z", ""),
        ]));
        assert_eq!(out.matches("---").count(), 0);
        assert!(!out.contains("10:33:00"));
        assert!(!out.contains("10:34:00"));
    }

    #[test]
    fn handles_empty_input() {
        assert_eq!(render_prompt(&mk(vec![])), "");
    }

    #[test]
    fn trims_per_recording_text() {
        let out = render_prompt(&mk(vec![("2026-04-15T10:32:00Z", "  hallo\n\n")]));
        assert!(out.ends_with("hallo"));
    }
}
