# views/destinataere.py
# Phase 0: Vision 2026 – Code-Refactoring

import csv
import io
import json
import os
import time
from datetime import datetime, timedelta, date
from decimal import Decimal

import qrcode
import qrcode.image.svg
import requests
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import (Avg, Count, DecimalField, F, IntegerField, Q,
                              Sum, Value)
from django.db.models.functions import Cast, Coalesce, NullIf, Replace
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django_otp.decorators import otp_required
from django_otp.plugins.otp_totp.models import TOTPDevice
from django_otp.plugins.otp_static.models import StaticDevice, StaticToken
from django_otp.util import random_hex
from rest_framework.decorators import api_view
from rest_framework.response import Response

from stiftung.audit import log_action
from stiftung.models import (AppConfiguration, AuditLog, BackupJob, BankTransaction,
                     BriefVorlage, CSVImport, Destinataer,
                     DestinataerEmailEingang, DestinataerNotiz,
                     DestinataerUnterstuetzung,
                     DokumentDatei, DokumentLink, Foerderung, GeschichteBild, GeschichteSeite,
                     Land, LandAbrechnung, LandVerpachtung, Paechter, Person,
                     Rentmeister, StiftungsKalenderEintrag, StiftungsKonto,
                     UnterstuetzungWiederkehrend, Veranstaltung,
                     Veranstaltungsteilnehmer, Verwaltungskosten,
                     VierteljahresNachweis)
from stiftung.forms import (
    DestinataerForm, DestinataerUnterstuetzungForm, DestinataerNotizForm,
    FoerderungForm, GeschichteBildForm, GeschichteSeiteForm,
    LandForm, LandVerpachtungForm, LandAbrechnungForm,
    PaechterForm, DokumentLinkForm,
    RentmeisterForm, StiftungsKontoForm, VerwaltungskostenForm,
    BankTransactionForm, BankImportForm,
    UnterstuetzungForm, UnterstuetzungWiederkehrendForm,
    UnterstuetzungMarkAsPaidForm, VierteljahresNachweisForm,
    UserCreationForm, UserUpdateForm, PasswordChangeForm, UserPermissionForm,
    TwoFactorSetupForm, TwoFactorVerifyForm, TwoFactorDisableForm,
    BackupTokenRegenerateForm, PersonForm,
    VeranstaltungForm, VeranstaltungsteilnehmerForm,
)


@login_required
def person_list(request):
    search_query = request.GET.get("search", "")
    familienzweig_filter = request.GET.get("familienzweig", "")
    aktiv_filter = request.GET.get("aktiv", "")

    persons = Person.objects.all()

    if search_query:
        persons = persons.filter(
            Q(nachname__icontains=search_query)
            | Q(vorname__icontains=search_query)
            | Q(email__icontains=search_query)
            | Q(familienzweig__icontains=search_query)
        )

    if familienzweig_filter:
        persons = persons.filter(familienzweig=familienzweig_filter)

    if aktiv_filter == "true":
        persons = persons.filter(aktiv=True)
    elif aktiv_filter == "false":
        persons = persons.filter(aktiv=False)

    # Annotate with total funding
    persons = persons.annotate(total_foerderungen=Sum("foerderung__betrag"))

    paginator = Paginator(persons, 20)
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    context = {
        "page_obj": page_obj,
        "search_query": search_query,
        "familienzweig_filter": familienzweig_filter,
        "aktiv_filter": aktiv_filter,
        "familienzweig_choices": Person.FAMILIENZWIG_CHOICES,
    }
    return render(request, "stiftung/person_list.html", context)


@login_required
def person_detail(request, pk):
    person = get_object_or_404(Person, pk=pk)
    foerderungen = person.foerderung_set.all().order_by("-jahr", "-betrag")
    # Get new LandVerpachtungen for this person's Paechter instances
    verpachtungen = LandVerpachtung.objects.filter(paechter__person=person).order_by(
        "-pachtbeginn"
    )

    context = {
        "person": person,
        "foerderungen": foerderungen,
        "verpachtungen": verpachtungen,
    }
    return render(request, "stiftung/person_detail.html", context)


@login_required
def person_create(request):
    if request.method == "POST":
        form = PersonForm(request.POST)
        if form.is_valid():
            person = form.save()
            messages.success(
                request,
                f'Person "{person.get_full_name()}" wurde erfolgreich erstellt.',
            )
            return redirect("stiftung:person_detail", pk=person.pk)
    else:
        form = PersonForm()

    context = {"form": form, "title": "Neue Person erstellen"}
    return render(request, "stiftung/person_form.html", context)


@login_required
def person_update(request, pk):
    person = get_object_or_404(Person, pk=pk)
    if request.method == "POST":
        form = PersonForm(request.POST, instance=person)
        if form.is_valid():
            person = form.save()
            messages.success(
                request,
                f'Person "{person.get_full_name()}" wurde erfolgreich aktualisiert.',
            )
            return redirect("stiftung:person_detail", pk=person.pk)
    else:
        form = PersonForm(instance=person)

    context = {
        "form": form,
        "person": person,
        "title": f"Person bearbeiten: {person.get_full_name()}",
    }
    return render(request, "stiftung/person_form.html", context)


@login_required
def person_delete(request, pk):
    person = get_object_or_404(Person, pk=pk)
    if request.method == "POST":
        person.delete()
        messages.success(
            request, f'Person "{person.get_full_name()}" wurde erfolgreich gelöscht.'
        )
        return redirect("stiftung:person_list")

    context = {"person": person}
    return render(request, "stiftung/person_confirm_delete.html", context)


# Destinatär Views (Förderungsempfänger)
@login_required
def destinataer_list(request):
    search_query = request.GET.get("search", "")
    familienzweig_filter = request.GET.get("familienzweig", "")
    berufsgruppe_filter = request.GET.get("berufsgruppe", "")
    aktiv_filter = request.GET.get("aktiv", "true")
    sort = request.GET.get("sort", "")
    direction = request.GET.get("dir", "asc")

    destinataere = Destinataer.objects.all()

    if search_query:
        destinataere = destinataere.filter(
            Q(nachname__icontains=search_query)
            | Q(vorname__icontains=search_query)
            | Q(email__icontains=search_query)
            | Q(institution__icontains=search_query)
            | Q(familienzweig__icontains=search_query)
        )

    if familienzweig_filter:
        destinataere = destinataere.filter(familienzweig=familienzweig_filter)

    if berufsgruppe_filter:
        destinataere = destinataere.filter(berufsgruppe=berufsgruppe_filter)

    if aktiv_filter == "true":
        destinataere = destinataere.filter(aktiv=True)
    elif aktiv_filter == "false":
        destinataere = destinataere.filter(aktiv=False)

    # Annotate with total funding (coalesce nulls to Decimal for stable sorting)
    destinataere = destinataere.annotate(
        total_foerderungen=Coalesce(
            Sum("foerderung__betrag"),
            Value(
                Decimal("0.00"),
                output_field=DecimalField(max_digits=12, decimal_places=2),
            ),
            output_field=DecimalField(max_digits=12, decimal_places=2),
        )
    )

    # Sorting
    sort_map = {
        "vorname": ["vorname"],
        "nachname": ["nachname"],
        "email": ["email"],
        "vierteljaehrlicher_betrag": ["vierteljaehrlicher_betrag"],
        "letzter_studiennachweis": ["letzter_studiennachweis"],
        "unterstuetzung_bestaetigt": ["unterstuetzung_bestaetigt"],
        # Keep old mappings for backward compatibility
        "name": ["nachname", "vorname"],
        "familienzweig": ["familienzweig"],
        "berufsgruppe": ["berufsgruppe"],
        "institution": ["institution"],
        "foerderungen": ["total_foerderungen"],
        "status": ["aktiv"],
    }
    if sort in sort_map:
        fields = sort_map[sort]
        if direction == "desc":
            order_fields = [f"-{f}" for f in fields]
        else:
            order_fields = fields
        destinataere = destinataere.order_by(*order_fields)
    else:
        # Default sorting by last name (nachname) ascending
        destinataere = destinataere.order_by("nachname", "vorname")

    paginator = Paginator(destinataere, 50)  # Increased from 20 to 50 entries per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    # Set default sort to nachname if no sort is specified
    effective_sort = sort if sort else "nachname"
    effective_direction = direction if sort else "asc"
    
    context = {
        "page_obj": page_obj,
        "search_query": search_query,
        "familienzweig_filter": familienzweig_filter,
        "berufsgruppe_filter": berufsgruppe_filter,
        "aktiv_filter": aktiv_filter,
        "familienzweig_choices": Destinataer.FAMILIENZWIG_CHOICES,
        "berufsgruppe_choices": Destinataer.BERUFSGRUPPE_CHOICES,
        "sort": effective_sort,
        "dir": effective_direction,
    }
    return render(request, "stiftung/destinataer_list.html", context)


@login_required
def destinataer_detail(request, pk):
    destinataer = get_object_or_404(Destinataer, pk=pk)

    # Alle mit diesem Destinatär verknüpften Dokumente laden
    verknuepfte_dokumente = DokumentDatei.objects.filter(
        destinataer=destinataer
    ).order_by("kontext", "titel")

    # Förderungen für diesen Destinatär laden
    foerderungen = Foerderung.objects.filter(destinataer=destinataer).order_by(
        "-jahr", "-betrag"
    )

    # Unterstützungen für diesen Destinatär laden
    unterstuetzungen = DestinataerUnterstuetzung.objects.filter(
        destinataer=destinataer
    ).order_by("-faellig_am")

    # Notizen laden
    notizen_eintraege = DestinataerNotiz.objects.filter(
        destinataer=destinataer
    ).order_by("-erstellt_am")

    # Quarterly confirmations - load for current and next year
    from datetime import date
    current_year = date.today().year
    quarterly_confirmations = VierteljahresNachweis.objects.filter(
        destinataer=destinataer,
        jahr__in=[current_year, current_year + 1]
    ).order_by('-jahr', '-quartal')

    # Create missing quarterly confirmations for current year
    # Quarterly tracking is now always available regardless of study proof requirements
    for quartal in range(1, 5):  # Q1-Q4
        nachweis, created = VierteljahresNachweis.get_or_create_for_period(
            destinataer, current_year, quartal
        )

    # Reload to get any newly created confirmations
    quarterly_confirmations = VierteljahresNachweis.objects.filter(
        destinataer=destinataer,
        jahr__in=[current_year, current_year + 1]
    ).order_by('-jahr', '-quartal')
    
    # Modal forms removed - only using full-screen editor now
    
    # Generate available years for the add quarter dropdown (current year + next 5 years)
    available_years = list(range(current_year, current_year + 6))

    # Alle verfügbaren StiftungsKonten für das Select-Feld laden
    stiftungskonten = StiftungsKonto.objects.all().order_by("kontoname")

    # Timeline events (merged from destinataer_timeline view)
    timeline_events = []
    for u in destinataer.unterstuetzungen.select_related("konto", "ausgezahlt_von", "freigegeben_von").order_by("-faellig_am"):
        timeline_events.append({
            "datum": u.faellig_am,
            "typ": "zahlung",
            "icon": "fa-money-bill-wave",
            "farbe": "success" if u.status == "ausgezahlt" else ("danger" if u.is_overdue() else "primary"),
            "titel": f"Zahlung \u20ac{u.betrag}",
            "beschreibung": u.beschreibung or u.get_status_display(),
            "status": u.get_status_display(),
        })
    for n in destinataer.quartalseinreichungen.order_by("-jahr", "-quartal"):
        datum = n.zahlung_faelligkeitsdatum or n.faelligkeitsdatum
        if datum:
            timeline_events.append({
                "datum": datum,
                "typ": "nachweis",
                "icon": "fa-file-alt",
                "farbe": "success" if n.status in ("geprueft", "auto_geprueft") else ("danger" if n.is_overdue() else "warning"),
                "titel": f"Nachweis {n.jahr} Q{n.quartal}",
                "beschreibung": n.get_status_display(),
                "status": n.get_status_display(),
            })
    for e in destinataer.email_eingaenge.order_by("-eingangsdatum"):
        timeline_events.append({
            "datum": e.eingangsdatum.date() if hasattr(e.eingangsdatum, "date") else e.eingangsdatum,
            "typ": "email",
            "icon": "fa-envelope",
            "farbe": "info",
            "titel": e.betreff or "(kein Betreff)",
            "beschreibung": e.absender_email,
            "status": e.get_status_display(),
        })
    for n in destinataer.notizen_eintraege.order_by("-erstellt_am"):
        timeline_events.append({
            "datum": n.erstellt_am.date() if hasattr(n.erstellt_am, "date") else n.erstellt_am,
            "typ": "notiz",
            "icon": "fa-sticky-note",
            "farbe": "secondary",
            "titel": n.titel or "Notiz",
            "beschreibung": (n.text[:100] + "\u2026") if n.text and len(n.text) > 100 else n.text,
            "status": f"von {n.erstellt_von.get_full_name() or n.erstellt_von.username}" if n.erstellt_von else "",
        })
    timeline_events.sort(key=lambda e: e["datum"] if e["datum"] else date.min, reverse=True)

    context = {
        "destinataer": destinataer,
        "verknuepfte_dokumente": verknuepfte_dokumente,
        "foerderungen": foerderungen,
        "unterstuetzungen": unterstuetzungen,
        "notizen_eintraege": notizen_eintraege,
        "stiftungskonten": stiftungskonten,
        "quarterly_confirmations": quarterly_confirmations,
        "available_years": available_years,
        "current_year": current_year,
        "timeline_events": timeline_events,
    }
    return render(request, "stiftung/destinataer_detail.html", context)


@login_required
def destinataer_create(request):
    if request.method == "POST":
        form = DestinataerForm(request.POST)
        if form.is_valid():
            destinataer = form.save()
            messages.success(
                request,
                f'Destinatär "{destinataer.get_full_name()}" wurde erfolgreich erstellt.',
            )
            return redirect("stiftung:destinataer_detail", pk=destinataer.pk)
    else:
        form = DestinataerForm()

    context = {"form": form, "title": "Neuen Destinatär erstellen"}
    return render(request, "stiftung/destinataer_form.html", context)


@login_required
def destinataer_update(request, pk):
    destinataer = get_object_or_404(Destinataer, pk=pk)
    if request.method == "POST":
        form = DestinataerForm(request.POST, instance=destinataer)
        
        # Handle AJAX requests
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            if form.is_valid():
                try:
                    destinataer = form.save()
                    
                    # Note: Support payments are now only created through quarterly confirmations
                    # No automatic creation when unterstuetzung_bestaetigt is checked
                    
                    return JsonResponse({
                        'success': True,
                        'message': f'Destinatär "{destinataer.get_full_name()}" wurde erfolgreich aktualisiert.'
                    })
                    
                except Exception as e:
                    return JsonResponse({
                        'success': False,
                        'error': f'Fehler beim Speichern: {str(e)}'
                    })
            else:
                # Return form errors for AJAX requests
                errors = []
                for field, field_errors in form.errors.items():
                    for error in field_errors:
                        errors.append(f'{form[field].label}: {error}')
                
                return JsonResponse({
                    'success': False,
                    'error': 'Formular enthält Fehler: ' + '; '.join(errors)
                })
        
        # Handle regular form submission
        if form.is_valid():
            destinataer = form.save()
            # Note: Support payments are now only created through quarterly confirmations
            # No automatic creation when unterstuetzung_bestaetigt is checked
            messages.success(
                request,
                f'Destinatär "{destinataer.get_full_name()}" wurde erfolgreich aktualisiert.',
            )
            return redirect("stiftung:destinataer_detail", pk=destinataer.pk)
    else:
        form = DestinataerForm(instance=destinataer)

    context = {
        "form": form,
        "destinataer": destinataer,
        "title": f"Destinatär bearbeiten: {destinataer.get_full_name()}",
    }
    return render(request, "stiftung/destinataer_form.html", context)


@login_required
def destinataer_delete(request, pk):
    destinataer = get_object_or_404(Destinataer, pk=pk)
    if request.method == "POST":
        destinataer.delete()
        messages.success(
            request,
            f'Destinatär "{destinataer.get_full_name()}" wurde erfolgreich gelöscht.',
        )
        return redirect("stiftung:destinataer_list")

    context = {"destinataer": destinataer}
    return render(request, "stiftung/destinataer_confirm_delete.html", context)


@login_required
def destinataer_toggle_archiv(request, pk):
    """Destinatär aktivieren/deaktivieren (archivieren)."""
    destinataer = get_object_or_404(Destinataer, pk=pk)
    if request.method == "POST":
        destinataer.aktiv = not destinataer.aktiv
        destinataer.save(update_fields=["aktiv"])
        status_text = "aktiviert" if destinataer.aktiv else "archiviert (inaktiv gesetzt)"
        log_action(
            request,
            action="update",
            entity_type="destinataer",
            entity_id=str(destinataer.pk),
            entity_name=destinataer.get_full_name(),
            description=f"Destinatär {destinataer.get_full_name()} wurde {status_text}.",
        )
        messages.success(request, f'Destinatär "{destinataer.get_full_name()}" wurde {status_text}.')
    return redirect("stiftung:destinataer_detail", pk=destinataer.pk)


# Paechter Views (Landpächter)
@login_required
def destinataer_notiz_create(request, pk):
    destinataer = get_object_or_404(Destinataer, pk=pk)
    if request.method == "POST":
        form = DestinataerNotizForm(request.POST, request.FILES)
        if form.is_valid():
            note = form.save(commit=False)
            note.destinataer = destinataer
            note.erstellt_von = request.user
            note.save()
            messages.success(request, "Notiz wurde gespeichert.")
            return redirect("stiftung:destinataer_detail", pk=destinataer.pk)
        else:
            # Debug: show what validation failed
            for field, errors in form.errors.items():
                messages.error(request, f'Fehler in {field}: {", ".join(errors)}')
    else:
        form = DestinataerNotizForm()
    return render(
        request,
        "stiftung/destinataer_notiz_form.html",
        {"form": form, "destinataer": destinataer, "title": "Notiz hinzufügen"},
    )


@login_required
def destinataer_export(request, pk):
    """Export complete Destinatär data as ZIP with documents"""
    import json
    import os
    import tempfile
    import zipfile

    from django.http import HttpResponse

    destinataer = get_object_or_404(Destinataer, pk=pk)

    # Create a temporary file for the ZIP
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".zip")

    try:
        with zipfile.ZipFile(temp_file.name, "w", zipfile.ZIP_DEFLATED) as zipf:
            # 1. Entity data as JSON
            entity_data = {
                "id": str(destinataer.id),
                "anrede": destinataer.get_anrede_display() if hasattr(destinataer, 'anrede') and destinataer.anrede else None,
                "titel": destinataer.titel if hasattr(destinataer, 'titel') else None,
                "vorname": destinataer.vorname,
                "nachname": destinataer.nachname,
                "geburtsdatum": (
                    destinataer.geburtsdatum.isoformat()
                    if destinataer.geburtsdatum
                    else None
                ),
                "email": destinataer.email,
                "telefon": destinataer.telefon,
                "mobil": destinataer.mobil if hasattr(destinataer, 'mobil') else None,
                "iban": destinataer.iban,
                "strasse": destinataer.strasse,
                "plz": destinataer.plz,
                "ort": destinataer.ort,
                "familienzweig": destinataer.get_familienzweig_display(),
                "berufsgruppe": destinataer.get_berufsgruppe_display(),
                "ausbildungsstand": destinataer.ausbildungsstand,
                "institution": destinataer.institution,
                "projekt_beschreibung": destinataer.projekt_beschreibung,
                "jaehrliches_einkommen": (
                    str(destinataer.jaehrliches_einkommen)
                    if destinataer.jaehrliches_einkommen
                    else None
                ),
                "finanzielle_notlage": destinataer.finanzielle_notlage,
                "ist_abkoemmling": destinataer.ist_abkoemmling,
                "haushaltsgroesse": destinataer.haushaltsgroesse,
                "monatliche_bezuege": (
                    str(destinataer.monatliche_bezuege)
                    if destinataer.monatliche_bezuege
                    else None
                ),
                "vermoegen": (
                    str(destinataer.vermoegen) if destinataer.vermoegen else None
                ),
                "unterstuetzung_bestaetigt": destinataer.unterstuetzung_bestaetigt,
                "vierteljaehrlicher_betrag": (
                    str(destinataer.vierteljaehrlicher_betrag)
                    if destinataer.vierteljaehrlicher_betrag
                    else None
                ),
                "standard_konto": (
                    str(destinataer.standard_konto)
                    if destinataer.standard_konto
                    else None
                ),
                "studiennachweis_erforderlich": destinataer.studiennachweis_erforderlich,
                "letzter_studiennachweis": (
                    destinataer.letzter_studiennachweis.isoformat()
                    if destinataer.letzter_studiennachweis
                    else None
                ),
                "notizen": destinataer.notizen,
                "aktiv": destinataer.aktiv,
                "export_datum": timezone.now().isoformat(),
                "export_user": request.user.username,
            }
            zipf.writestr(
                "destinataer_data.json",
                json.dumps(entity_data, indent=2, ensure_ascii=False),
            )

            # 2. Notes with attachments
            notizen = DestinataerNotiz.objects.filter(destinataer=destinataer).order_by(
                "-erstellt_am"
            )
            notes_data = []
            for note in notizen:
                note_data = {
                    "titel": note.titel,
                    "text": note.text,
                    "erstellt_am": note.erstellt_am.isoformat(),
                    "erstellt_von": (
                        note.erstellt_von.username if note.erstellt_von else None
                    ),
                    "datei_name": note.datei.name if note.datei else None,
                }
                notes_data.append(note_data)

                # Add attachment file if exists
                if note.datei and os.path.exists(note.datei.path):
                    zipf.write(
                        note.datei.path,
                        f"notizen_anhaenge/{os.path.basename(note.datei.name)}",
                    )

            if notes_data:
                zipf.writestr(
                    "notizen.json", json.dumps(notes_data, indent=2, ensure_ascii=False)
                )

            # 3. Linked documents from Paperless
            dokumente = DokumentLink.objects.filter(destinataer_id=destinataer.pk)
            docs_data = []
            for doc in dokumente:
                doc_data = {
                    "paperless_id": doc.paperless_document_id,
                    "titel": doc.titel,
                    "kontext": doc.get_kontext_display(),
                    "beschreibung": doc.beschreibung,
                }
                docs_data.append(doc_data)

                # Try to download document from Paperless
                try:
                    if (
                        hasattr(settings, "PAPERLESS_API_URL")
                        and settings.PAPERLESS_API_URL
                    ):
                        doc_url = f"{settings.PAPERLESS_API_URL}/api/documents/{doc.paperless_document_id}/download/"
                        headers = {}
                        if (
                            hasattr(settings, "PAPERLESS_API_TOKEN")
                            and settings.PAPERLESS_API_TOKEN
                        ):
                            headers["Authorization"] = (
                                f"Token {settings.PAPERLESS_API_TOKEN}"
                            )

                        response = requests.get(doc_url, headers=headers, timeout=30)
                        if response.status_code == 200:
                            # Determine file extension from Content-Type or use .pdf as fallback
                            content_type = response.headers.get("content-type", "")
                            if "pdf" in content_type:
                                ext = ".pdf"
                            elif "jpeg" in content_type or "jpg" in content_type:
                                ext = ".jpg"
                            elif "png" in content_type:
                                ext = ".png"
                            else:
                                ext = ".pdf"  # fallback

                            safe_filename = f"dokument_{doc.paperless_document_id}_{doc.titel.replace('/', '_')[:50]}{ext}"
                            zipf.writestr(
                                f"dokumente/{safe_filename}", response.content
                            )
                            doc_data["downloaded"] = True
                        else:
                            doc_data["download_error"] = f"HTTP {response.status_code}"
                except Exception as e:
                    doc_data["download_error"] = str(e)

            if docs_data:
                zipf.writestr(
                    "dokumente.json",
                    json.dumps(docs_data, indent=2, ensure_ascii=False),
                )

            # 4. Quarterly Confirmations with documents
            quarterly_confirmations = destinataer.quartalseinreichungen.all().order_by("-jahr", "-quartal")
            quarterly_data = []
            
            for confirmation in quarterly_confirmations:
                confirmation_data = {
                    "id": str(confirmation.id),
                    "jahr": confirmation.jahr,
                    "quartal": confirmation.quartal,
                    "quartal_display": confirmation.get_quartal_display(),
                    "status": confirmation.status,
                    "status_display": confirmation.get_status_display(),
                    "studiennachweis_erforderlich": confirmation.studiennachweis_erforderlich,
                    "studiennachweis_eingereicht": confirmation.studiennachweis_eingereicht,
                    "studiennachweis_bemerkung": confirmation.studiennachweis_bemerkung,
                    "einkommenssituation_bestaetigt": confirmation.einkommenssituation_bestaetigt,
                    "einkommenssituation_text": confirmation.einkommenssituation_text,
                    "vermogenssituation_bestaetigt": confirmation.vermogenssituation_bestaetigt,
                    "vermogenssituation_text": confirmation.vermogenssituation_text,
                    "weitere_dokumente_beschreibung": confirmation.weitere_dokumente_beschreibung,
                    "interne_notizen": confirmation.interne_notizen,
                    "erstellt_am": confirmation.erstellt_am.isoformat(),
                    "aktualisiert_am": confirmation.aktualisiert_am.isoformat(),
                    "eingereicht_am": confirmation.eingereicht_am.isoformat() if confirmation.eingereicht_am else None,
                    "geprueft_am": confirmation.geprueft_am.isoformat() if confirmation.geprueft_am else None,
                    "geprueft_von": confirmation.geprueft_von.username if confirmation.geprueft_von else None,
                    "faelligkeitsdatum": confirmation.faelligkeitsdatum.isoformat() if confirmation.faelligkeitsdatum else None,
                    "completion_percentage": confirmation.get_completion_percentage(),
                    "uploaded_files": []
                }
                
                # Add uploaded files from quarterly confirmation
                quarterly_files = [
                    ("studiennachweis", confirmation.studiennachweis_datei),
                    ("einkommenssituation", confirmation.einkommenssituation_datei),
                    ("vermogenssituation", confirmation.vermogenssituation_datei),
                    ("weitere_dokumente", confirmation.weitere_dokumente),
                ]
                
                for file_type, file_field in quarterly_files:
                    if file_field and os.path.exists(file_field.path):
                        file_info = {
                            "type": file_type,
                            "name": os.path.basename(file_field.name),
                            "path": file_field.name
                        }
                        confirmation_data["uploaded_files"].append(file_info)
                        
                        # Add file to ZIP
                        safe_filename = f"quarterly_{confirmation.jahr}_Q{confirmation.quartal}_{file_type}_{os.path.basename(file_field.name)}"
                        zipf.write(
                            file_field.path,
                            f"vierteljahresnachweis/{safe_filename}"
                        )
                
                quarterly_data.append(confirmation_data)
            
            if quarterly_data:
                zipf.writestr(
                    "vierteljahresnachweis.json",
                    json.dumps(quarterly_data, indent=2, ensure_ascii=False),
                )

        # Prepare response
        with open(temp_file.name, "rb") as f:
            response = HttpResponse(f.read(), content_type="application/zip")
            filename = f"destinataer_{destinataer.nachname}_{destinataer.vorname}_{timezone.now().strftime('%Y%m%d_%H%M%S')}.zip"
            response["Content-Disposition"] = f'attachment; filename="{filename}"'
            return response

    finally:
        # Clean up temp file
        try:
            os.unlink(temp_file.name)
        except:
            pass


# =============================================================================
# Bestätigungsschreiben
# =============================================================================

@login_required
def bestaetigung_vorschau(request, pk):
    """
    PDF-Vorschau eines Bestätigungsschreibens für einen Destinatär im Browser.
    Generiert das PDF on-the-fly via WeasyPrint.
    """
    from decimal import Decimal
    from django.template.loader import render_to_string

    destinataer = get_object_or_404(Destinataer, id=pk)

    unterstuetzungen = DestinataerUnterstuetzung.objects.filter(
        destinataer=destinataer,
        status__in=["ausgezahlt", "abgeschlossen"],
    ).order_by("faellig_am")

    gesamtbetrag = unterstuetzungen.aggregate(total=Sum("betrag"))["total"] or Decimal("0")

    zeitraum = None
    if unterstuetzungen.exists():
        erste = unterstuetzungen.first().faellig_am
        letzte = unterstuetzungen.last().faellig_am
        if erste == letzte:
            zeitraum = erste.strftime("%d.%m.%Y")
        else:
            zeitraum = f"{erste.strftime('%d.%m.%Y')} – {letzte.strftime('%d.%m.%Y')}"

    betrag_quartal = destinataer.vierteljaehrlicher_betrag
    betrag_jaehrlich = (betrag_quartal * 4) if betrag_quartal else None
    zweck = destinataer.ausbildungsstand or (destinataer.get_berufsgruppe_display() if destinataer.berufsgruppe else None)

    context = {
        "destinataer": destinataer,
        "unterstuetzungen": unterstuetzungen,
        "gesamtbetrag": gesamtbetrag,
        "datum": timezone.now().date(),
        "zeitraum": zeitraum,
        "betrag_quartal": betrag_quartal,
        "betrag_jaehrlich": betrag_jaehrlich,
        "zweck": zweck,
    }

    try:
        from weasyprint import HTML
        from stiftung.utils.vorlagen import render_vorlage
        html_content = render_vorlage("pdf/bestaetigung.html", context)
        pdf_bytes = HTML(string=html_content).write_pdf()
        response = HttpResponse(pdf_bytes, content_type="application/pdf")
        filename = f"bestaetigung_{destinataer.nachname}_{destinataer.vorname}.pdf"
        response["Content-Disposition"] = f'inline; filename="{filename}"'
        return response
    except Exception as exc:
        messages.error(request, f"PDF-Generierung fehlgeschlagen: {exc}")
        return redirect("stiftung:destinataer_detail", pk=pk)


@login_required
def bestaetigung_versenden(request, pk):
    """
    Sendet das Bestätigungsschreiben per E-Mail an den Destinatär.
    POST-only (CSRF-geschützt). Sendet synchron für direktes Feedback.
    """
    from stiftung.tasks import _send_bestaetigung_sync

    if request.method != "POST":
        return redirect("stiftung:destinataer_detail", pk=pk)

    destinataer = get_object_or_404(Destinataer, id=pk)

    if not destinataer.email:
        messages.error(
            request,
            f"Destinatär {destinataer.get_full_name()} hat keine E-Mail-Adresse hinterlegt.",
        )
        return redirect("stiftung:destinataer_detail", pk=pk)

    try:
        result = _send_bestaetigung_sync(str(destinataer.id))
    except Exception as exc:
        import logging
        logging.getLogger(__name__).exception("Bestätigung versenden fehlgeschlagen: %s", exc)
        messages.error(
            request,
            f"Bestätigungsschreiben konnte nicht gesendet werden: {exc}",
        )
        return redirect("stiftung:destinataer_detail", pk=pk)

    if result and result.get("status") == "skipped":
        messages.warning(request, "Versand übersprungen: Keine E-Mail-Adresse hinterlegt.")
        return redirect("stiftung:destinataer_detail", pk=pk)

    if result and result.get("status") == "error":
        messages.error(request, f"Fehler: {result.get('message', 'Unbekannter Fehler')}")
        return redirect("stiftung:destinataer_detail", pk=pk)

    log_action(
        request,
        action="update",
        entity_type="destinataer",
        entity_id=str(destinataer.id),
        entity_name=destinataer.get_full_name(),
        description=f"Bestätigungsschreiben per E-Mail gesendet an {destinataer.get_full_name()} ({destinataer.email})",
    )

    messages.success(
        request,
        f"Bestätigungsschreiben wurde erfolgreich an {destinataer.email} gesendet.",
    )
    return redirect("stiftung:destinataer_detail", pk=pk)

