from datetime import datetime

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

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

router = APIRouter(prefix="/veranstaltungen")
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 = "",
    kampagne_id: int = None,
    von: str = "",
    bis: str = "",
    q: str = "",
    ort: str = "",
):
    query = db.query(Veranstaltung).options(
        joinedload(Veranstaltung.teilnehmer),
        joinedload(Veranstaltung.kampagne),
    )

    if status:
        query = query.filter(Veranstaltung.status == status)
    if typ:
        query = query.filter(Veranstaltung.typ == typ)
    if kampagne_id:
        query = query.filter(Veranstaltung.kampagne_id == kampagne_id)
    if von:
        try:
            from datetime import datetime as _dt
            query = query.filter(Veranstaltung.start_datum >= _dt.fromisoformat(von))
        except ValueError:
            pass
    if bis:
        try:
            from datetime import datetime as _dt, timedelta
            query = query.filter(Veranstaltung.start_datum < _dt.fromisoformat(bis) + timedelta(days=1))
        except ValueError:
            pass

    if q:
        query = query.filter(Veranstaltung.titel.ilike(f"%{q}%"))
    if ort:
        query = query.filter(Veranstaltung.ort.ilike(f"%{ort}%"))

    veranstaltungen = query.order_by(Veranstaltung.start_datum.desc()).all()

    # Filter-Dropdowns
    alle_typen = [r[0] for r in db.query(Veranstaltung.typ).filter(Veranstaltung.typ.isnot(None)).distinct().order_by(Veranstaltung.typ).all()]
    alle_kampagnen = db.query(Kampagne).order_by(Kampagne.titel).all()

    return templates.TemplateResponse("pages/veranstaltungen/liste.html", {
        "request": request,
        "user": user,
        "active_page": "veranstaltungen",
        "veranstaltungen": veranstaltungen,
        "alle_typen": alle_typen,
        "alle_kampagnen": alle_kampagnen,
        "f_status": status,
        "f_typ": typ,
        "f_kampagne_id": kampagne_id,
        "f_von": von,
        "f_bis": bis,
        "f_q": q,
        "f_ort": ort,
    })


def _load_projekte(db: Session) -> list[str]:
    pv = [r[0] for r in db.query(Veranstaltung.projekt).filter(Veranstaltung.projekt.isnot(None)).distinct().all()]
    pk = [r[0] for r in db.query(Kampagne.projekt).filter(Kampagne.projekt.isnot(None)).distinct().all()]
    return sorted(set(pv + pk))


@router.get("/neu", response_class=HTMLResponse)
async def neu_formular(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    return templates.TemplateResponse("pages/veranstaltungen/formular.html", {
        "request": request,
        "user": user,
        "active_page": "veranstaltungen",
        "veranstaltung": None,
        "projekte": _load_projekte(db),
    })


@router.post("/neu")
async def erstellen(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    form = await request.form()
    v = Veranstaltung(
        titel=form["titel"],
        beschreibung=form.get("beschreibung") or None,
        ort=form.get("ort") or None,
        typ=form.get("typ") or None,
        status=form.get("status", "geplant"),
        projekt=form.get("projekt_neu") or form.get("projekt") or None,
        erfasst_von=user.kuerzel,
    )
    if form.get("start_datum"):
        try:
            v.start_datum = datetime.fromisoformat(form["start_datum"])
        except ValueError:
            pass
    if form.get("end_datum"):
        try:
            v.end_datum = datetime.fromisoformat(form["end_datum"])
        except ValueError:
            pass
    if form.get("max_teilnehmer"):
        v.max_teilnehmer = int(form["max_teilnehmer"])

    db.add(v)
    db.flush()
    search.index_veranstaltung(db, v)
    db.commit()
    return RedirectResponse(url=f"/veranstaltungen/{v.id}", status_code=303)


@router.get("/{v_id}", response_class=HTMLResponse)
async def detail(v_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    v = (
        db.query(Veranstaltung)
        .options(joinedload(Veranstaltung.teilnehmer).joinedload(Teilnehmer.kontakt))
        .filter(Veranstaltung.id == v_id)
        .first()
    )
    if not v:
        return RedirectResponse(url="/veranstaltungen", status_code=303)

    # Alle Kontakte laden, bereits zugeordnete ausfiltern
    teilnehmer_ids = {tn.kontakt_id for tn in v.teilnehmer}
    alle_kontakte = db.query(Kontakt).filter(
        Kontakt.ist_blacklisted == False
    ).order_by(Kontakt.nachname, Kontakt.firmenname).all()
    verfuegbare_kontakte = [k for k in alle_kontakte if k.id not in teilnehmer_ids]

    # Aktivitaeten dieser Veranstaltung laden
    aktivitaeten = (
        db.query(Aktivitaet)
        .filter(Aktivitaet.veranstaltung_id == v_id)
        .order_by(Aktivitaet.datum.desc())
        .all()
    )

    # Alle Kampagnen fuer Zuordnung
    alle_kampagnen = db.query(Kampagne).order_by(Kampagne.titel).all()

    return templates.TemplateResponse("pages/veranstaltungen/detail.html", {
        "request": request,
        "user": user,
        "active_page": "veranstaltungen",
        "veranstaltung": v,
        "alle_kontakte": verfuegbare_kontakte,
        "aktivitaeten": aktivitaeten,
        "alle_kampagnen": alle_kampagnen,
    })


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

    return templates.TemplateResponse("pages/veranstaltungen/formular.html", {
        "request": request,
        "user": user,
        "active_page": "veranstaltungen",
        "veranstaltung": v,
        "projekte": _load_projekte(db),
    })


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

    form = await request.form()
    v.titel = form["titel"]
    v.beschreibung = form.get("beschreibung") or None
    v.ort = form.get("ort") or None
    v.typ = form.get("typ") or None
    v.status = form.get("status", "geplant")
    v.projekt = form.get("projekt_neu") or form.get("projekt") or None

    if form.get("start_datum"):
        try:
            v.start_datum = datetime.fromisoformat(form["start_datum"])
        except ValueError:
            pass
    if form.get("end_datum"):
        try:
            v.end_datum = datetime.fromisoformat(form["end_datum"])
        except ValueError:
            pass
    if form.get("max_teilnehmer"):
        v.max_teilnehmer = int(form["max_teilnehmer"])

    db.flush()
    search.index_veranstaltung(db, v)
    db.commit()
    return RedirectResponse(url=f"/veranstaltungen/{v_id}", status_code=303)


@router.get("/{v_id}/loeschen")
async def loeschen(v_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    v = db.query(Veranstaltung).filter(Veranstaltung.id == v_id).first()
    if v:
        db.delete(v)
        db.commit()
    return RedirectResponse(url="/veranstaltungen", status_code=303)


# --- Teilnehmer CRUD ---

@router.post("/{v_id}/teilnehmer", response_class=HTMLResponse)
async def teilnehmer_hinzufuegen(
    v_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kontakt_id = int(form["kontakt_id"])
    rolle = form.get("rolle", "teilnehmer")

    # Pruefen ob bereits Teilnehmer
    existing = db.query(Teilnehmer).filter(
        Teilnehmer.veranstaltung_id == v_id,
        Teilnehmer.kontakt_id == kontakt_id,
    ).first()

    if not existing:
        tn = Teilnehmer(veranstaltung_id=v_id, kontakt_id=kontakt_id, rolle=rolle)
        db.add(tn)
        db.commit()

    return _render_teilnehmer(db, v_id, request)


@router.post("/{v_id}/teilnehmer/{tn_id}/status", response_class=HTMLResponse)
async def teilnehmer_status_update(
    v_id: int,
    tn_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    tn = db.query(Teilnehmer).filter(
        Teilnehmer.id == tn_id,
        Teilnehmer.veranstaltung_id == v_id,
    ).first()
    if tn:
        tn.status = form["status"]
        db.commit()
    return _render_teilnehmer(db, v_id, request)


@router.delete("/{v_id}/teilnehmer/{tn_id}", response_class=HTMLResponse)
async def teilnehmer_entfernen(
    v_id: int,
    tn_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    tn = db.query(Teilnehmer).filter(Teilnehmer.id == tn_id).first()
    if tn:
        db.delete(tn)
        db.commit()

    return _render_teilnehmer(db, v_id, request)


# --- Kampagne-Zuordnung ---

@router.post("/{v_id}/kampagne")
async def kampagne_zuordnen(
    v_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kampagne_id = form.get("kampagne_id")
    v = db.query(Veranstaltung).filter(Veranstaltung.id == v_id).first()
    if v:
        v.kampagne_id = int(kampagne_id) if kampagne_id else None
        db.commit()
    return RedirectResponse(url=f"/veranstaltungen/{v_id}", status_code=303)


@router.post("/{v_id}/teilnehmer-aus-kampagne")
async def teilnehmer_aus_kampagne(
    v_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    kampagne_status = form.get("kampagne_status") or None

    v = db.query(Veranstaltung).filter(Veranstaltung.id == v_id).first()
    if not v or not v.kampagne_id:
        return RedirectResponse(url=f"/veranstaltungen/{v_id}", status_code=303)

    bestehende_ids = {tn.kontakt_id for tn in db.query(Teilnehmer).filter(Teilnehmer.veranstaltung_id == v_id).all()}

    query = db.query(KampagneKontakt).filter(KampagneKontakt.kampagne_id == v.kampagne_id)
    if kampagne_status:
        query = query.filter(KampagneKontakt.status == kampagne_status)

    for kk in query.all():
        if kk.kontakt_id not in bestehende_ids:
            db.add(Teilnehmer(veranstaltung_id=v_id, kontakt_id=kk.kontakt_id, rolle="teilnehmer"))
            bestehende_ids.add(kk.kontakt_id)

    db.commit()
    return RedirectResponse(url=f"/veranstaltungen/{v_id}", status_code=303)


def _render_teilnehmer(db: Session, v_id: int, request: Request):
    teilnehmer_liste = (
        db.query(Teilnehmer)
        .options(joinedload(Teilnehmer.kontakt))
        .filter(Teilnehmer.veranstaltung_id == v_id)
        .all()
    )
    teilnehmer_ids = {tn.kontakt_id for tn in teilnehmer_liste}
    alle_kontakte = db.query(Kontakt).filter(
        Kontakt.ist_blacklisted == False
    ).order_by(Kontakt.nachname, Kontakt.firmenname).all()
    verfuegbare_kontakte = [k for k in alle_kontakte if k.id not in teilnehmer_ids]

    return templates.TemplateResponse("components/teilnehmer.html", {
        "request": request,
        "teilnehmer_liste": teilnehmer_liste,
        "veranstaltung_id": v_id,
        "alle_kontakte": verfuegbare_kontakte,
    })
