"""
Lese-Tools für den MCP Server der Stiftungsverwaltung.

Alle Tools:
  - Prüfen die Rolle (readonly/editor/admin erforderlich)
  - Wenden PII-Maskierung an (außer bei admin)
  - Schreiben Audit-Log-Einträge
"""

from __future__ import annotations

from django.db.models import Q, Sum

from mcp_server.audit import log_mcp_read
from mcp_server.auth import require_role
from mcp_server.privacy import apply_privacy_filter, apply_privacy_filter_list
from mcp_server.tools.helpers import format_result, model_to_dict


def _get_role() -> str:
    from mcp_server.auth import get_current_role, require_role as _require
    role = get_current_role()
    _require(role)
    return role


# ──────────────────────────────────────────────────────────────────────────────
# Destinatäre
# ──────────────────────────────────────────────────────────────────────────────

def destinataer_suchen(
    suchbegriff: str = "",
    aktiv: bool | None = None,
    familienzweig: str = "",
    limit: int = 20,
) -> str:
    """
    Sucht Destinatäre nach Name, Familienzweig oder Aktivstatus.

    Args:
        suchbegriff: Freitext (Vor-/Nachname, Institution)
        aktiv: True=nur Aktive, False=nur Inaktive, None=alle
        familienzweig: Filtert nach Familienzweig (hauptzweig/nebenzweig/verwandt/anderer)
        limit: Maximale Anzahl Ergebnisse (max. 100)
    """
    from stiftung.models import Destinataer

    role = _get_role()
    limit = min(limit, 100)

    qs = Destinataer.objects.all()
    if suchbegriff:
        qs = qs.filter(
            Q(vorname__icontains=suchbegriff)
            | Q(nachname__icontains=suchbegriff)
            | Q(institution__icontains=suchbegriff)
        )
    if aktiv is not None:
        qs = qs.filter(aktiv=aktiv)
    if familienzweig:
        qs = qs.filter(familienzweig=familienzweig)

    qs = qs.order_by("nachname", "vorname")[:limit]

    # Reduzierte Felder für Listen-Ausgabe
    results = []
    for obj in qs:
        item = {
            "id": str(obj.id),
            "vorname": obj.vorname,
            "nachname": obj.nachname,
            "familienzweig": obj.familienzweig,
            "aktiv": obj.aktiv,
            "berufsgruppe": obj.berufsgruppe,
            "ort": obj.ort,
            "email": obj.email,
        }
        results.append(apply_privacy_filter(item, "destinataer", role))

    log_mcp_read(role, "destinataer", "Destinatär-Suche", f"Suche: '{suchbegriff}', {len(results)} Ergebnisse")
    return format_result({"anzahl": len(results), "destinataere": results})


def destinataer_details(destinataer_id: str) -> str:
    """
    Gibt vollständige Details eines Destinatärs zurück.

    Args:
        destinataer_id: UUID des Destinatärs
    """
    from stiftung.models import Destinataer, DestinataerUnterstuetzung, Foerderung

    role = _get_role()

    try:
        obj = Destinataer.objects.get(id=destinataer_id)
    except Destinataer.DoesNotExist:
        return format_result({"fehler": f"Destinatär {destinataer_id} nicht gefunden"})

    data = model_to_dict(obj)
    data = apply_privacy_filter(data, "destinataer", role)

    # Aktuelle Unterstützungen
    unterstuetzungen = list(
        DestinataerUnterstuetzung.objects.filter(destinataer=obj)
        .exclude(status="storniert")
        .order_by("-faellig_am")[:10]
        .values("id", "betrag", "faellig_am", "status", "beschreibung")
    )
    for u in unterstuetzungen:
        for k, v in u.items():
            from mcp_server.tools.helpers import serialize_value
            u[k] = serialize_value(v)

    # Förderungen
    foerderungen = list(
        Foerderung.objects.filter(destinataer=obj)
        .order_by("-jahr")[:10]
        .values("id", "jahr", "betrag", "kategorie", "status")
    )
    for f in foerderungen:
        for k, v in f.items():
            from mcp_server.tools.helpers import serialize_value
            f[k] = serialize_value(v)

    data["aktuelle_unterstuetzungen"] = unterstuetzungen
    data["foerderungen"] = foerderungen

    name = f"{obj.vorname} {obj.nachname}"
    log_mcp_read(role, "destinataer", name, f"Details abgerufen für {name}")
    return format_result(data)


# ──────────────────────────────────────────────────────────────────────────────
# Ländereien
# ──────────────────────────────────────────────────────────────────────────────

def land_suchen(
    suchbegriff: str = "",
    gemeinde: str = "",
    limit: int = 20,
) -> str:
    """
    Sucht Ländereien nach Bezeichnung, Gemarkung oder Gemeinde.

    Args:
        suchbegriff: Freitext (Bezeichnung, Gemarkung)
        gemeinde: Filtert nach Gemeinde
        limit: Maximale Anzahl Ergebnisse (max. 100)
    """
    from stiftung.models import Land

    role = _get_role()
    limit = min(limit, 100)

    qs = Land.objects.all()
    if suchbegriff:
        qs = qs.filter(
            Q(gemeinde__icontains=suchbegriff)
            | Q(gemarkung__icontains=suchbegriff)
            | Q(flur__icontains=suchbegriff)
            | Q(lfd_nr__icontains=suchbegriff)
            | Q(adresse__icontains=suchbegriff)
        )
    if gemeinde:
        qs = qs.filter(gemeinde__icontains=gemeinde)

    qs = qs.order_by("gemeinde", "gemarkung")[:limit]

    results = []
    for obj in qs:
        results.append({
            "id": str(obj.id),
            "bezeichnung": str(obj),
            "lfd_nr": obj.lfd_nr,
            "gemeinde": obj.gemeinde,
            "gemarkung": obj.gemarkung,
            "flur": obj.flur,
            "flurstueck": obj.flurstueck,
            "groesse_qm": float(obj.groesse_qm) if obj.groesse_qm else None,
            "aktiv_verpachtet": obj.neue_verpachtungen.filter(status="aktiv").exists(),
        })

    log_mcp_read(role, "land", "Länderei-Suche", f"Suche: '{suchbegriff}', {len(results)} Ergebnisse")
    return format_result({"anzahl": len(results), "laendereien": results})


def land_details(land_id: str) -> str:
    """
    Gibt vollständige Details einer Länderei zurück.

    Args:
        land_id: UUID der Länderei
    """
    from stiftung.models import Land, LandVerpachtung

    role = _get_role()

    try:
        obj = Land.objects.get(id=land_id)
    except Land.DoesNotExist:
        return format_result({"fehler": f"Länderei {land_id} nicht gefunden"})

    data = model_to_dict(obj)

    # Aktive Verpachtungen
    verpachtungen = []
    for v in obj.neue_verpachtungen.all().order_by("-pachtbeginn")[:5]:
            verpachtungen.append({
                "id": str(v.id),
                "paechter": str(v.paechter) if v.paechter else None,
                "pachtbeginn": v.pachtbeginn.isoformat() if v.pachtbeginn else None,
                "pachtende": v.pachtende.isoformat() if v.pachtende else None,
                "pachtzins_pauschal": float(v.pachtzins_pauschal) if v.pachtzins_pauschal else None,
                "status": v.status,
            })

    data["verpachtungen"] = verpachtungen
    log_mcp_read(role, "land", str(obj), f"Land-Details abgerufen: {obj}")
    return format_result(data)


# ──────────────────────────────────────────────────────────────────────────────
# Pächter
# ──────────────────────────────────────────────────────────────────────────────

def paechter_suchen(
    suchbegriff: str = "",
    limit: int = 20,
) -> str:
    """
    Sucht Pächter nach Name.

    Args:
        suchbegriff: Freitext (Vor-/Nachname)
        limit: Maximale Anzahl Ergebnisse (max. 100)
    """
    from stiftung.models import Paechter

    role = _get_role()
    limit = min(limit, 100)

    qs = Paechter.objects.all()
    if suchbegriff:
        qs = qs.filter(
            Q(vorname__icontains=suchbegriff) | Q(nachname__icontains=suchbegriff)
        )

    qs = qs.order_by("nachname", "vorname")[:limit]

    results = []
    for obj in qs:
        item = {
            "id": str(obj.id),
            "vorname": obj.vorname,
            "nachname": obj.nachname,
            "personentyp": obj.personentyp,
            "ort": obj.ort,
            "email": obj.email,
            "telefon": obj.telefon,
            "aktive_verpachtungen": obj.neue_verpachtungen.filter(status="aktiv").count() if hasattr(obj, "neue_verpachtungen") else 0,
        }
        results.append(apply_privacy_filter(item, "paechter", role))

    log_mcp_read(role, "paechter", "Pächter-Suche", f"Suche: '{suchbegriff}', {len(results)} Ergebnisse")
    return format_result({"anzahl": len(results), "paechter": results})


# ──────────────────────────────────────────────────────────────────────────────
# Konten
# ──────────────────────────────────────────────────────────────────────────────

def konten_uebersicht() -> str:
    """
    Gibt eine Übersicht aller Stiftungskonten mit aktuellem Saldo zurück.
    """
    from stiftung.models import StiftungsKonto

    role = _get_role()

    konten = []
    gesamt_saldo = 0.0
    for konto in StiftungsKonto.objects.filter(aktiv=True).order_by("bank_name"):
        saldo = float(konto.saldo) if konto.saldo else 0.0
        gesamt_saldo += saldo
        konten.append({
            "id": str(konto.id),
            "kontoname": konto.kontoname,
            "bank_name": konto.bank_name,
            "konto_typ": konto.konto_typ,
            "saldo": saldo,
            "saldo_datum": konto.saldo_datum.isoformat() if konto.saldo_datum else None,
            "zinssatz": float(konto.zinssatz) if konto.zinssatz else None,
            # IBAN nur für Admin
            "iban": konto.iban if role == "admin" else "****" + konto.iban[-4:] if konto.iban and len(konto.iban) > 4 else "****",
        })

    log_mcp_read(role, "stiftungskonto", "Kontenübersicht", f"{len(konten)} Konten abgerufen")
    return format_result({
        "konten": konten,
        "gesamt_saldo": round(gesamt_saldo, 2),
        "anzahl_konten": len(konten),
    })


# ──────────────────────────────────────────────────────────────────────────────
# Verwaltungskosten
# ──────────────────────────────────────────────────────────────────────────────

def verwaltungskosten(
    jahr: int | None = None,
    kategorie: str = "",
    status: str = "",
    limit: int = 50,
) -> str:
    """
    Listet Verwaltungskosten auf.

    Args:
        jahr: Filtert nach Jahr (z.B. 2024)
        kategorie: Filtert nach Kategorie (rechnung_intern, bueroausstattung, ...)
        status: Filtert nach Status (geplant, bezahlt, ...)
        limit: Maximale Anzahl (max. 200)
    """
    from stiftung.models import Verwaltungskosten

    role = _get_role()
    limit = min(limit, 200)

    qs = Verwaltungskosten.objects.all()
    if jahr:
        qs = qs.filter(datum__year=jahr)
    if kategorie:
        qs = qs.filter(kategorie=kategorie)
    if status:
        qs = qs.filter(status=status)

    qs = qs.order_by("-datum")[:limit]

    results = []
    gesamt = 0.0
    for obj in qs:
        betrag = float(obj.betrag) if obj.betrag else 0.0
        gesamt += betrag
        results.append({
            "id": str(obj.id),
            "bezeichnung": obj.bezeichnung,
            "kategorie": obj.kategorie,
            "betrag": betrag,
            "datum": obj.datum.isoformat(),
            "lieferant_firma": obj.lieferant_firma,
            "status": obj.status,
            "rechnungsnummer": obj.rechnungsnummer,
        })

    log_mcp_read(role, "verwaltungskosten", "Verwaltungskosten", f"{len(results)} Einträge")
    return format_result({
        "anzahl": len(results),
        "gesamt_betrag": round(gesamt, 2),
        "verwaltungskosten": results,
    })


# ──────────────────────────────────────────────────────────────────────────────
# Transaktionen
# ──────────────────────────────────────────────────────────────────────────────

def transaktionen_suchen(
    suchbegriff: str = "",
    konto_id: str = "",
    von_datum: str = "",
    bis_datum: str = "",
    transaction_type: str = "",
    limit: int = 50,
) -> str:
    """
    Sucht Banktransaktionen.

    Args:
        suchbegriff: Freitext in Verwendungszweck oder Empfänger
        konto_id: UUID des Kontos (optional)
        von_datum: Startdatum YYYY-MM-DD (optional)
        bis_datum: Enddatum YYYY-MM-DD (optional)
        transaction_type: eingang/ausgang/dauerauftrag/... (optional)
        limit: Maximale Anzahl (max. 200)
    """
    from stiftung.models import BankTransaction

    role = _get_role()
    limit = min(limit, 200)

    qs = BankTransaction.objects.select_related("konto").all()
    if suchbegriff:
        qs = qs.filter(
            Q(verwendungszweck__icontains=suchbegriff)
            | Q(empfaenger_zahlungspflichtiger__icontains=suchbegriff)
        )
    if konto_id:
        qs = qs.filter(konto_id=konto_id)
    if von_datum:
        qs = qs.filter(datum__gte=von_datum)
    if bis_datum:
        qs = qs.filter(datum__lte=bis_datum)
    if transaction_type:
        qs = qs.filter(transaction_type=transaction_type)

    qs = qs.order_by("-datum")[:limit]

    results = []
    for obj in qs:
        results.append({
            "id": str(obj.id),
            "datum": obj.datum.isoformat(),
            "betrag": float(obj.betrag),
            "waehrung": obj.waehrung,
            "verwendungszweck": obj.verwendungszweck[:200],
            "empfaenger_zahlungspflichtiger": obj.empfaenger_zahlungspflichtiger,
            "transaction_type": obj.transaction_type,
            "status": obj.status,
            "konto": obj.konto.kontoname if obj.konto else None,
        })

    log_mcp_read(role, "banktransaction", "Transaktionssuche", f"Suche: '{suchbegriff}', {len(results)} Ergebnisse")
    return format_result({"anzahl": len(results), "transaktionen": results})


# ──────────────────────────────────────────────────────────────────────────────
# Dokumente
# ──────────────────────────────────────────────────────────────────────────────

def dokument_suchen(
    suchbegriff: str = "",
    kontext: str = "",
    limit: int = 30,
) -> str:
    """
    Sucht Dokumente im DMS nach Titel, Beschreibung oder Kontext.

    Args:
        suchbegriff: Freitext (Titel, Beschreibung, Volltext)
        kontext: Dokumententyp (pachtvertrag, antrag, rechnung, ...)
        limit: Maximale Anzahl (max. 100)
    """
    from stiftung.models import DokumentDatei

    role = _get_role()
    limit = min(limit, 100)

    qs = DokumentDatei.objects.all()
    if suchbegriff:
        qs = qs.filter(
            Q(titel__icontains=suchbegriff)
            | Q(beschreibung__icontains=suchbegriff)
            | Q(inhaltstext__icontains=suchbegriff)
        )
    if kontext:
        qs = qs.filter(kontext=kontext)

    qs = qs.order_by("-erstellt_am")[:limit]

    results = []
    for obj in qs:
        results.append({
            "id": str(obj.id),
            "titel": obj.titel,
            "kontext": obj.kontext,
            "beschreibung": obj.beschreibung[:200] if obj.beschreibung else "",
            "dateityp": obj.dateityp,
            "dateigroesse": obj.dateigroesse,
            "dateiname_original": obj.dateiname_original,
        })

    log_mcp_read(role, "dokumentlink", "Dokumentsuche", f"Suche: '{suchbegriff}', {len(results)} Ergebnisse")
    return format_result({"anzahl": len(results), "dokumente": results})


def dokument_details(dokument_id: str) -> str:
    """
    Gibt Details eines Dokuments zurück (ohne Dateiinhalt).

    Args:
        dokument_id: UUID des Dokuments
    """
    from stiftung.models import DokumentDatei

    role = _get_role()

    try:
        obj = DokumentDatei.objects.get(id=dokument_id)
    except DokumentDatei.DoesNotExist:
        return format_result({"fehler": f"Dokument {dokument_id} nicht gefunden"})

    data = {
        "id": str(obj.id),
        "titel": obj.titel,
        "kontext": obj.kontext,
        "beschreibung": obj.beschreibung,
        "dateityp": obj.dateityp,
        "dateigroesse": obj.dateigroesse,
        "dateiname_original": obj.dateiname_original,
        # Verknüpfungen
        "land_id": str(obj.land_id) if obj.land_id else None,
        "paechter_id": str(obj.paechter_id) if obj.paechter_id else None,
    }
    # Inhaltstext nur für Nicht-Binary-Dokumente und wenn vorhanden
    if obj.inhaltstext:
        data["inhaltsvorschau"] = obj.inhaltstext[:500]

    log_mcp_read(role, "dokumentlink", obj.titel, f"Dokumentdetails abgerufen: {obj.titel}")
    return format_result(data)


# ──────────────────────────────────────────────────────────────────────────────
# Termine
# ──────────────────────────────────────────────────────────────────────────────

def termine_anzeigen(
    von_datum: str = "",
    bis_datum: str = "",
    kategorie: str = "",
    prioritaet: str = "",
    limit: int = 50,
) -> str:
    """
    Zeigt Kalendereinträge und Termine an.

    Args:
        von_datum: Startdatum YYYY-MM-DD (optional, Standard: heute)
        bis_datum: Enddatum YYYY-MM-DD (optional)
        kategorie: termin/zahlung/deadline/geburtstag/vertrag/pruefung/sonstiges
        prioritaet: niedrig/normal/hoch/kritisch
        limit: Maximale Anzahl (max. 200)
    """
    from datetime import date as date_type
    from stiftung.models import StiftungsKalenderEintrag

    role = _get_role()
    limit = min(limit, 200)

    qs = StiftungsKalenderEintrag.objects.all()
    if von_datum:
        qs = qs.filter(datum__gte=von_datum)
    else:
        qs = qs.filter(datum__gte=date_type.today())
    if bis_datum:
        qs = qs.filter(datum__lte=bis_datum)
    if kategorie:
        qs = qs.filter(kategorie=kategorie)
    if prioritaet:
        qs = qs.filter(prioritaet=prioritaet)

    qs = qs.order_by("datum", "uhrzeit")[:limit]

    results = []
    for obj in qs:
        results.append({
            "id": str(obj.id),
            "titel": obj.titel,
            "datum": obj.datum.isoformat(),
            "uhrzeit": obj.uhrzeit.isoformat() if obj.uhrzeit else None,
            "ganztags": obj.ganztags,
            "kategorie": obj.kategorie,
            "prioritaet": obj.prioritaet,
            "beschreibung": obj.beschreibung[:300] if obj.beschreibung else "",
            "destinataer_id": str(obj.destinataer_id) if obj.destinataer_id else None,
        })

    log_mcp_read(role, "system", "Terminübersicht", f"{len(results)} Termine abgerufen")
    return format_result({"anzahl": len(results), "termine": results})


# ──────────────────────────────────────────────────────────────────────────────
# Veranstaltungen
# ──────────────────────────────────────────────────────────────────────────────

def veranstaltungen_anzeigen(
    status: str = "",
    limit: int = 20,
) -> str:
    """
    Zeigt Veranstaltungen der Stiftung an.

    Args:
        status: geplant/einladungen_versendet/abgeschlossen/abgesagt (optional, leer = alle)
        limit: Maximale Anzahl (max. 50)
    """
    from stiftung.models.veranstaltungen import Veranstaltung

    role = _get_role()
    limit = min(limit, 50)

    qs = Veranstaltung.objects.all()
    if status:
        qs = qs.filter(status=status)

    qs = qs.order_by("-datum")[:limit]

    results = []
    for v in qs:
        results.append({
            "id": str(v.id),
            "titel": v.titel,
            "datum": v.datum.isoformat(),
            "uhrzeit": v.uhrzeit.isoformat() if v.uhrzeit else None,
            "ort": v.ort,
            "status": v.status,
            "teilnehmer_gesamt": v.get_teilnehmer_count(),
            "zugesagt": v.get_zugesagte_count(),
            "abgesagt": v.get_abgesagte_count(),
        })

    log_mcp_read(role, "veranstaltung", "Veranstaltungsübersicht", f"{len(results)} Veranstaltungen")
    return format_result({"anzahl": len(results), "veranstaltungen": results})


def veranstaltung_teilnehmer_anzeigen(
    veranstaltung_id: str,
    rsvp_status: str = "",
) -> str:
    """
    Zeigt die Teilnehmer einer Veranstaltung an.

    Args:
        veranstaltung_id: UUID der Veranstaltung (Pflichtfeld)
        rsvp_status: eingeladen/zugesagt/abgesagt/keine_rueckmeldung (optional, leer = alle)
    """
    from stiftung.models.veranstaltungen import Veranstaltung

    role = _get_role()

    try:
        veranstaltung = Veranstaltung.objects.get(id=veranstaltung_id)
    except Veranstaltung.DoesNotExist:
        return format_result({"fehler": f"Veranstaltung {veranstaltung_id} nicht gefunden"})

    qs = veranstaltung.teilnehmer.all()
    if rsvp_status:
        qs = qs.filter(rsvp_status=rsvp_status)

    results = []
    for t in qs:
        results.append({
            "id": str(t.id),
            "anrede": t.anrede,
            "vorname": t.vorname,
            "nachname": t.nachname,
            "strasse": t.strasse,
            "plz": t.plz,
            "ort": t.ort,
            "email": t.email,
            "rsvp_status": t.rsvp_status,
            "destinataer_id": str(t.destinataer_id) if t.destinataer_id else None,
        })

    log_mcp_read(
        role, "veranstaltung", str(veranstaltung.id),
        f"{len(results)} Teilnehmer von '{veranstaltung.titel}'",
    )
    return format_result({
        "veranstaltung": str(veranstaltung),
        "anzahl": len(results),
        "teilnehmer": results,
    })


# ──────────────────────────────────────────────────────────────────────────────
# Globale Suche & Dashboard
# ──────────────────────────────────────────────────────────────────────────────

def globale_suche(suchbegriff: str, limit_pro_typ: int = 5) -> str:
    """
    Sucht über alle Entitätstypen gleichzeitig.

    Args:
        suchbegriff: Suchbegriff (mindestens 2 Zeichen)
        limit_pro_typ: Ergebnisse pro Entitätstyp (max. 20)
    """
    from stiftung.models import (
        BankTransaction, Destinataer, Land, Paechter,
        StiftungsKalenderEintrag, Verwaltungskosten,
    )

    role = _get_role()

    if len(suchbegriff) < 2:
        return format_result({"fehler": "Suchbegriff muss mindestens 2 Zeichen lang sein"})

    limit_pro_typ = min(limit_pro_typ, 20)
    ergebnisse = {}

    # Destinatäre
    dest = Destinataer.objects.filter(
        Q(vorname__icontains=suchbegriff) | Q(nachname__icontains=suchbegriff)
    )[:limit_pro_typ]
    ergebnisse["destinataere"] = [
        {"id": str(d.id), "name": f"{d.vorname} {d.nachname}", "typ": "destinataer"}
        for d in dest
    ]

    # Ländereien
    laender = Land.objects.filter(
        Q(bezeichnung__icontains=suchbegriff) | Q(gemarkung__icontains=suchbegriff)
    )[:limit_pro_typ]
    ergebnisse["laendereien"] = [
        {"id": str(l.id), "name": str(l), "typ": "land"}
        for l in laender
    ]

    # Pächter
    paechter = Paechter.objects.filter(
        Q(vorname__icontains=suchbegriff) | Q(nachname__icontains=suchbegriff)
    )[:limit_pro_typ]
    ergebnisse["paechter"] = [
        {"id": str(p.id), "name": f"{p.vorname} {p.nachname}", "typ": "paechter"}
        for p in paechter
    ]

    # Transaktionen
    transaktionen = BankTransaction.objects.filter(
        Q(verwendungszweck__icontains=suchbegriff)
        | Q(empfaenger_zahlungspflichtiger__icontains=suchbegriff)
    )[:limit_pro_typ]
    ergebnisse["transaktionen"] = [
        {"id": str(t.id), "verwendungszweck": t.verwendungszweck[:100], "betrag": float(t.betrag), "datum": t.datum.isoformat(), "typ": "transaktion"}
        for t in transaktionen
    ]

    log_mcp_read(role, "system", "Globale Suche", f"Suche: '{suchbegriff}'")
    return format_result(ergebnisse)


def dashboard() -> str:
    """
    Gibt eine Übersicht der wichtigsten Stiftungsdaten zurück.
    """
    from datetime import date as date_type
    from stiftung.models import (
        BankTransaction, Destinataer, DestinataerUnterstuetzung,
        Land, LandVerpachtung, StiftungsKalenderEintrag, StiftungsKonto,
    )

    role = _get_role()
    heute = date_type.today()

    # Konten-Gesamtsaldo
    konten = StiftungsKonto.objects.filter(aktiv=True)
    gesamt_saldo = sum(float(k.saldo or 0) for k in konten)

    # Destinatäre
    aktive_dest = Destinataer.objects.filter(aktiv=True).count()

    # Offene Zahlungen
    offene_zahlungen = DestinataerUnterstuetzung.objects.filter(
        status__in=["geplant", "faellig", "nachweis_eingereicht", "freigegeben"]
    ).aggregate(anzahl=Sum("betrag"))
    offene_zahlungen_betrag = float(offene_zahlungen["anzahl"] or 0)
    offene_zahlungen_anzahl = DestinataerUnterstuetzung.objects.filter(
        status__in=["geplant", "faellig", "nachweis_eingereicht", "freigegeben"]
    ).count()

    # Fällige Termine (nächste 30 Tage)
    from datetime import timedelta
    naechste_termine = StiftungsKalenderEintrag.objects.filter(
        datum__gte=heute,
        datum__lte=heute + timedelta(days=30),
    ).order_by("datum")[:5]

    termine_liste = [
        {"titel": t.titel, "datum": t.datum.isoformat(), "prioritaet": t.prioritaet, "kategorie": t.kategorie}
        for t in naechste_termine
    ]

    # Aktive Verpachtungen
    aktive_verpachtungen = LandVerpachtung.objects.filter(status="aktiv").count()

    log_mcp_read(role, "system", "Dashboard", "Dashboard abgerufen")
    return format_result({
        "stand": heute.isoformat(),
        "finanzen": {
            "gesamt_saldo_eur": round(gesamt_saldo, 2),
            "anzahl_konten": konten.count(),
        },
        "destinataere": {
            "aktiv": aktive_dest,
        },
        "zahlungen": {
            "offen_anzahl": offene_zahlungen_anzahl,
            "offen_betrag_eur": round(offene_zahlungen_betrag, 2),
        },
        "verpachtungen": {
            "aktiv": aktive_verpachtungen,
        },
        "naechste_termine": termine_liste,
    })


def statistiken() -> str:
    """
    Gibt detaillierte Statistiken der Stiftungsverwaltung zurück.
    """
    from datetime import date as date_type
    from stiftung.models import (
        BankTransaction, Destinataer, Foerderung,
        Land, LandVerpachtung, Verwaltungskosten,
    )

    role = _get_role()
    aktuelles_jahr = date_type.today().year

    # Förderungen dieses Jahr
    foerderungen_jahr = Foerderung.objects.filter(jahr=aktuelles_jahr)
    foerderungen_gesamt = foerderungen_jahr.aggregate(summe=Sum("betrag"))

    # Destinatäre nach Familienzweig
    from django.db.models import Count
    dest_zweige = list(
        Destinataer.objects.filter(aktiv=True)
        .values("familienzweig")
        .annotate(anzahl=Count("id"))
        .order_by("-anzahl")
    )

    # Verwaltungskosten dieses Jahr
    vk_jahr = Verwaltungskosten.objects.filter(datum__year=aktuelles_jahr)
    vk_gesamt = vk_jahr.aggregate(summe=Sum("betrag"))

    # Ländereien
    laender_ges = Land.objects.count()
    laender_verpachtet = Land.objects.filter(
        neue_verpachtungen__status="aktiv"
    ).distinct().count()

    log_mcp_read(role, "system", "Statistiken", f"Statistiken für {aktuelles_jahr} abgerufen")
    return format_result({
        "jahr": aktuelles_jahr,
        "foerderungen": {
            "anzahl": foerderungen_jahr.count(),
            "gesamt_betrag_eur": float(foerderungen_gesamt["summe"] or 0),
        },
        "verwaltungskosten": {
            "anzahl": vk_jahr.count(),
            "gesamt_betrag_eur": float(vk_gesamt["summe"] or 0),
        },
        "destinataere_nach_zweig": dest_zweige,
        "laendereien": {
            "gesamt": laender_ges,
            "aktiv_verpachtet": laender_verpachtet,
        },
    })
