"""Kampagnen - Kontaktsammlungen fuer Mailings, Telefonaktionen etc."""

import csv
import io
from datetime import datetime

from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session, joinedload

from dependencies import get_current_user, get_db
from models.aktivitaet import Aktivitaet
from models.kampagne import Kampagne, KampagneKontakt
from models.kontakt import Kontakt
from models.spende import Spende
from models.veranstaltung import Veranstaltung
import search

router = APIRouter(prefix="/kampagnen")
templates = Jinja2Templates(directory="templates")


@router.get("", response_class=HTMLResponse)
async def liste(
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
    status: str = "",
    typ: str = "",
    projekt: str = "",
    q: str = "",
):
    query = db.query(Kampagne).options(
        joinedload(Kampagne.kontakte),
        joinedload(Kampagne.spenden),
    )
    if status:
        query = query.filter(Kampagne.status == status)
    if typ:
        query = query.filter(Kampagne.typ == typ)
    if projekt:
        query = query.filter(Kampagne.projekt == projekt)

    if q:
        from sqlalchemy import or_
        like = f"%{q}%"
        query = query.filter(or_(
            Kampagne.titel.ilike(like),
            Kampagne.beschreibung.ilike(like),
        ))

    kampagnen = query.order_by(Kampagne.erstellt_am.desc()).all()
    alle_projekte = [
        r[0] for r in
        db.query(Kampagne.projekt).filter(Kampagne.projekt.isnot(None)).distinct().order_by(Kampagne.projekt).all()
    ]

    return templates.TemplateResponse("pages/kampagnen/liste.html", {
        "request": request,
        "user": user,
        "active_page": "kampagnen",
        "kampagnen": kampagnen,
        "alle_projekte": alle_projekte,
        "typ_labels": Kampagne.TYP_LABELS,
        "f_status": status,
        "f_typ": typ,
        "f_projekt": projekt,
        "f_q": q,
    })


@router.get("/neu", response_class=HTMLResponse)
async def neu_formular(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    projekte = [r[0] for r in db.query(Kampagne.projekt).filter(Kampagne.projekt.isnot(None)).distinct().order_by(Kampagne.projekt).all()]
    return templates.TemplateResponse("pages/kampagnen/formular.html", {
        "request": request,
        "user": user,
        "active_page": "kampagnen",
        "kampagne": None,
        "projekte": projekte,
    })


@router.post("/neu")
async def erstellen(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    form = await request.form()
    projekt = form.get("projekt_neu") or form.get("projekt") or None
    k = Kampagne(
        titel=form["titel"],
        beschreibung=form.get("beschreibung") or None,
        typ=form.get("typ") or "sonstiges",
        status=form.get("status", "entwurf"),
        projekt=projekt,
        erstellt_von=user.kuerzel,
    )
    db.add(k)
    db.flush()
    search.index_kampagne(db, k)
    db.commit()
    return RedirectResponse(url=f"/kampagnen/{k.id}", status_code=303)


@router.get("/{k_id}", response_class=HTMLResponse)
async def detail(k_id: int, request: Request, bulk_status: str = "", bulk_notiz: str = "", user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = (
        db.query(Kampagne)
        .options(joinedload(Kampagne.kontakte).joinedload(KampagneKontakt.kontakt))
        .filter(Kampagne.id == k_id)
        .first()
    )
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    # KPI-Zaehlung (dynamisch aus DB-Optionen)
    from collections import Counter
    status_counter = Counter(kk.status for kk in k.kontakte)
    status_counts = dict(status_counter)

    # Aktivitaeten dieser Kampagne laden
    aktivitaeten = (
        db.query(Aktivitaet)
        .filter(Aktivitaet.kampagne_id == k_id)
        .order_by(Aktivitaet.datum.desc())
        .all()
    )

    # Veranstaltungen dieser Kampagne
    veranstaltungen = (
        db.query(Veranstaltung)
        .filter(Veranstaltung.kampagne_id == k_id)
        .order_by(Veranstaltung.start_datum.desc())
        .all()
    )

    # Spenden dieser Kampagne
    spenden = (
        db.query(Spende)
        .options(joinedload(Spende.kontakt))
        .filter(Spende.kampagne_id == k_id)
        .order_by(Spende.datum.desc())
        .all()
    )
    spenden_summe = sum(s.betrag for s in spenden)

    # Alle Kontakte fuer Schnell-Hinzufuegen (noch nicht in Kampagne)
    bestehende_ids = {kk.kontakt_id for kk in k.kontakte}
    all_kontakte = (
        db.query(Kontakt)
        .filter(Kontakt.ist_blacklisted == False)
        .order_by(Kontakt.nachname, Kontakt.firmenname)
        .all()
    )
    verfuegbare_kontakte = [c for c in all_kontakte if c.id not in bestehende_ids]

    return templates.TemplateResponse("pages/kampagnen/detail.html", {
        "request": request,
        "user": user,
        "active_page": "kampagnen",
        "kampagne": k,
        "status_counts": status_counts,
        "aktivitaeten": aktivitaeten,
        "veranstaltungen": veranstaltungen,
        "spenden": spenden,
        "spenden_summe": spenden_summe,
        "verfuegbare_kontakte": verfuegbare_kontakte,
        "bulk_status": bulk_status,
        "bulk_notiz": bulk_notiz,
    })


@router.get("/{k_id}/bearbeiten", response_class=HTMLResponse)
async def bearbeiten_formular(k_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    projekte = [r[0] for r in db.query(Kampagne.projekt).filter(Kampagne.projekt.isnot(None)).distinct().order_by(Kampagne.projekt).all()]
    return templates.TemplateResponse("pages/kampagnen/formular.html", {
        "request": request,
        "user": user,
        "active_page": "kampagnen",
        "kampagne": k,
        "projekte": projekte,
    })


@router.post("/{k_id}/bearbeiten")
async def aktualisieren(k_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    form = await request.form()
    k.titel = form["titel"]
    k.beschreibung = form.get("beschreibung") or None
    k.typ = form.get("typ") or "sonstiges"
    k.status = form.get("status", "entwurf")
    k.projekt = form.get("projekt_neu") or form.get("projekt") or None
    k.aktualisiert_am = datetime.now()

    db.flush()
    search.index_kampagne(db, k)
    db.commit()
    return RedirectResponse(url=f"/kampagnen/{k_id}", status_code=303)


@router.get("/{k_id}/loeschen")
async def loeschen(k_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    if k:
        search._remove_from_index(db, "kampagne", k.id)
        db.delete(k)
        db.commit()
    return RedirectResponse(url="/kampagnen", status_code=303)


# --- Kontakt direkt hinzufuegen (HTMX) ---

@router.post("/{k_id}/kontakte", response_class=HTMLResponse)
async def kontakt_hinzufuegen(
    k_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kontakt_id = int(form["kontakt_id"])

    existing = db.query(KampagneKontakt).filter(
        KampagneKontakt.kampagne_id == k_id,
        KampagneKontakt.kontakt_id == kontakt_id,
    ).first()

    if existing:
        return HTMLResponse("")

    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    kk = KampagneKontakt(
        kampagne_id=k_id,
        kontakt_id=kontakt_id,
        hinzugefuegt_von=user.kuerzel,
    )
    db.add(kk)
    db.flush()

    # Aktivitaet: Hinzufuegen zur Kampagne dokumentieren
    db.add(Aktivitaet(
        kontakt_id=kontakt_id,
        art="notiz",
        betreff=f"Zur Kampagne hinzugefügt: {k.titel if k else k_id}",
        status="information",
        datum=datetime.now(),
        kampagne_id=k_id,
        erfasst_von=user.kuerzel,
    ))
    db.commit()
    return _render_kontakt_row(db, kk.id, request)


# --- Bulk: Status/Notiz fuer alle Kontakte ---

@router.post("/{k_id}/kontakte/bulk")
async def kontakte_bulk_update(
    k_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    neuer_status = form.get("bulk_status") or None
    neue_notiz = form.get("bulk_notiz") or None
    als_aktivitaet = form.get("als_aktivitaet") == "1"

    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    kks = db.query(KampagneKontakt).filter(KampagneKontakt.kampagne_id == k_id).all()
    for kk in kks:
        if neuer_status:
            kk.status = neuer_status
        if neue_notiz is not None:
            kk.notiz = neue_notiz or kk.notiz

    # Eine einzige Sammel-Aktivität für die gesamte Kampagne (nicht eine pro Kontakt)
    if als_aktivitaet and (neuer_status or neue_notiz):
        teile = []
        if neuer_status:
            teile.append(f"Status: {KampagneKontakt.STATUS_LABELS.get(neuer_status, neuer_status)}")
        if neue_notiz:
            teile.append(f"Notiz: {neue_notiz}")
        db.add(Aktivitaet(
            art="notiz",
            betreff=f"Kampagne: {k.titel}",
            bemerkung=f"Bulk-Aktion für {len(kks)} Kontakte — " + ", ".join(teile),
            status="information",
            datum=datetime.now(),
            kampagne_id=k_id,
            erfasst_von=user.kuerzel,
        ))

    db.commit()
    # Bei "Uebernehmen" (nicht Als Aktivitaet): Werte in URL erhalten, damit man danach noch "Als Aktivitaet" druecken kann
    if not als_aktivitaet:
        from urllib.parse import urlencode
        params = {}
        if neuer_status:
            params["bulk_status"] = neuer_status
        if neue_notiz:
            params["bulk_notiz"] = neue_notiz
        qs = ("?" + urlencode(params)) if params else ""
        return RedirectResponse(url=f"/kampagnen/{k_id}{qs}", status_code=303)
    return RedirectResponse(url=f"/kampagnen/{k_id}", status_code=303)


# --- Kontakt-Status per HTMX ---

@router.post("/{k_id}/kontakte/{kk_id}/status", response_class=HTMLResponse)
async def kontakt_status_update(
    k_id: int,
    kk_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kk = db.query(KampagneKontakt).filter(KampagneKontakt.id == kk_id).first()
    if kk:
        kk.status = form.get("status", kk.status)
        db.commit()

    return _render_kontakt_row(db, kk_id, request)


@router.post("/{k_id}/kontakte/{kk_id}/notiz", response_class=HTMLResponse)
async def kontakt_notiz_update(
    k_id: int,
    kk_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kk = db.query(KampagneKontakt).filter(KampagneKontakt.id == kk_id).first()
    if kk:
        kk.notiz = form.get("notiz") or None
        db.commit()

    return _render_kontakt_row(db, kk_id, request)


@router.post("/{k_id}/kontakte/{kk_id}/als-aktivitaet", response_class=HTMLResponse)
async def kontakt_als_aktivitaet(
    k_id: int,
    kk_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kk = db.query(KampagneKontakt).filter(KampagneKontakt.id == kk_id).first()
    k = db.query(Kampagne).filter(Kampagne.id == k_id).first()
    if kk and k:
        notiz = form.get("notiz") or kk.notiz or None
        kk.notiz = notiz  # auch speichern
        teile = []
        teile.append(f"Status: {KampagneKontakt.STATUS_LABELS.get(kk.status, kk.status)}")
        if notiz:
            teile.append(f"Notiz: {notiz}")
        db.add(Aktivitaet(
            kontakt_id=kk.kontakt_id,
            art="notiz",
            betreff=f"Kampagne: {k.titel}",
            bemerkung="\n".join(teile),
            status="information",
            datum=datetime.now(),
            kampagne_id=k_id,
            erfasst_von=user.kuerzel,
        ))
        db.commit()

    return _render_kontakt_row(db, kk_id, request)


@router.delete("/{k_id}/kontakte/{kk_id}", response_class=HTMLResponse)
async def kontakt_entfernen(
    k_id: int,
    kk_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    kk = db.query(KampagneKontakt).filter(KampagneKontakt.id == kk_id).first()
    if kk:
        db.delete(kk)
        db.commit()
    return HTMLResponse("")


# --- Export ---

@router.get("/{k_id}/export/csv")
async def export_csv(k_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = (
        db.query(Kampagne)
        .options(joinedload(Kampagne.kontakte).joinedload(KampagneKontakt.kontakt))
        .filter(Kampagne.id == k_id)
        .first()
    )
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    output = io.StringIO()
    writer = csv.writer(output, delimiter=";")
    writer.writerow([
        "Status", "Anrede", "Titel", "Vorname", "Nachname", "Firmenname",
        "Position", "E-Mail", "Telefon", "Mobil", "Ort", "Notiz",
    ])
    for kk in k.kontakte:
        c = kk.kontakt
        writer.writerow([
            kk.status_label, c.anrede or "", c.titel or "", c.vorname or "",
            c.nachname or "", c.firmenname or "", c.position or "",
            c.email1 or "", c.telefon or "", c.mobil or "", c.ort or "",
            kk.notiz or "",
        ])

    content = output.getvalue()
    dateiname = f"kampagne_{k.titel[:30].replace(' ', '_')}.csv"
    return StreamingResponse(
        io.BytesIO(content.encode("utf-8-sig")),
        media_type="text/csv; charset=utf-8",
        headers={"Content-Disposition": f"attachment; filename={dateiname}"},
    )


@router.get("/{k_id}/export/emails")
async def export_emails(k_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    k = (
        db.query(Kampagne)
        .options(joinedload(Kampagne.kontakte).joinedload(KampagneKontakt.kontakt))
        .filter(Kampagne.id == k_id)
        .first()
    )
    if not k:
        return RedirectResponse(url="/kampagnen", status_code=303)

    emails = [kk.kontakt.email1 for kk in k.kontakte if kk.kontakt.email1]
    content = "\n".join(emails)

    return StreamingResponse(
        io.BytesIO(content.encode("utf-8")),
        media_type="text/plain; charset=utf-8",
        headers={"Content-Disposition": "attachment; filename=email_liste.txt"},
    )


def _render_kontakt_row(db: Session, kk_id: int, request: Request):
    kk = (
        db.query(KampagneKontakt)
        .options(joinedload(KampagneKontakt.kontakt))
        .filter(KampagneKontakt.id == kk_id)
        .first()
    )
    if not kk:
        return HTMLResponse("")

    c = kk.kontakt
    from services.kategorie_service import get_optionen, get_farben_dict
    from database import SessionLocal as _SL
    _db = _SL()
    try:
        kk_opts = get_optionen(_db, "kampagne_kontakt_status")
        kk_farben = get_farben_dict(_db, "kampagne_kontakt_status")
    finally:
        _db.close()

    status_options = ""
    for opt in kk_opts:
        selected = " selected" if opt.wert == kk.status else ""
        status_options += f'<option value="{opt.wert}"{selected}>{opt.label}</option>'

    color = kk_farben.get(kk.status, "#607D8B")
    notiz_safe = (kk.notiz or "").replace('"', '&quot;')

    html = f"""<tr id="kk-{kk.id}">
        <td style="font-weight: 500;"><a href="/kontakte/{c.id}">{c.anzeigename}</a></td>
        <td style="font-size: 0.85rem;">{c.firmenname or '-'}</td>
        <td style="font-size: 0.85rem;">{c.email1 or '-'}</td>
        <td style="font-size: 0.85rem;">{c.telefon or c.mobil or '-'}</td>
        <td>
            <select name="status" style="margin: 0; padding: 0.2rem 0.4rem; font-size: 0.8rem; border-color: {color}; color: {color}; min-width: 110px;"
                    hx-post="/kampagnen/{kk.kampagne_id}/kontakte/{kk.id}/status"
                    hx-target="#kk-{kk.id}" hx-swap="outerHTML">{status_options}</select>
        </td>
        <td>
            <div style="display: flex; gap: 0.25rem; align-items: center;">
                <input type="text" name="notiz" id="notiz-{kk.id}" value="{notiz_safe}"
                       placeholder="Notiz..."
                       style="margin: 0; padding: 0.2rem 0.4rem; font-size: 0.8rem; min-width: 120px;"
                       hx-post="/kampagnen/{kk.kampagne_id}/kontakte/{kk.id}/notiz"
                       hx-target="#kk-{kk.id}" hx-swap="outerHTML"
                       hx-trigger="blur changed">
                <button class="btn-icon" title="Als Aktivität speichern"
                        style="font-size: 0.75rem; padding: 0.1rem 0.3rem; flex-shrink: 0;"
                        hx-post="/kampagnen/{kk.kampagne_id}/kontakte/{kk.id}/als-aktivitaet"
                        hx-include="#notiz-{kk.id}"
                        hx-target="#kk-{kk.id}" hx-swap="outerHTML">📋</button>
            </div>
        </td>
        <td>
            <button class="btn-icon" style="font-size: 0.75rem; padding: 0.1rem 0.3rem; color: #e53e3e; border: 1px solid #e53e3e;"
                    hx-delete="/kampagnen/{kk.kampagne_id}/kontakte/{kk.id}"
                    hx-target="#kk-{kk.id}" hx-swap="outerHTML"
                    hx-confirm="Kontakt aus Kampagne entfernen?">x</button>
        </td>
    </tr>"""
    return HTMLResponse(html)
