from datetime import datetime

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

from dependencies import get_current_user, get_db
from models.branche import Branche, KontaktBranche
from models.beziehung import Beziehung
from models.gruppe import Gruppe, KontaktGruppe
from models.kontakt import Kontakt
from models.tag import KontaktTag, Tag, TagKategorie
from services import kontakt_service, export_service
import search

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


@router.get("", response_class=HTMLResponse)
async def liste(
    request: Request,
    seite: str = "1",
    sortierung: str = "nachname",
    buchstabe: str = None,
    gruppe: str = None,
    tag: str = None,
    q: str = None,
    ort: str = None,
    email: str = None,
    position: str = None,
    betreuer: str = None,
    eigentuemer: str = None,
    org_name: str = None,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    seite_int = int(seite) if seite and seite.isdigit() else 1
    gruppe_id = int(gruppe) if gruppe and gruppe.isdigit() else None
    tag_id = int(tag) if tag and tag.isdigit() else None
    ergebnis = kontakt_service.liste(
        db, typ="person", seite=seite_int, sortierung=sortierung,
        buchstabe=buchstabe, gruppe_id=gruppe_id, tag_id=tag_id, freitext=q,
        ort=ort, email=email, position=position,
        betreuer=betreuer, eigentuemer=eigentuemer, org_name=org_name,
    )
    gruppen = db.query(Gruppe).order_by(Gruppe.name).all()

    # Org-Zuordnung per Person laden (person_id -> org Kontakt)
    from sqlalchemy.orm import joinedload as jl
    person_ids = [k.id for k in ergebnis["kontakte"]]
    org_map = {}
    if person_ids:
        bezs = (db.query(Beziehung)
            .options(jl(Beziehung.kontakt_b))
            .filter(
                Beziehung.kontakt_a_id.in_(person_ids),
                Beziehung.typ.in_(["mitarbeiter_von", "vorstand_von", "mitglied_von"]),
            ).all())
        for bez in bezs:
            if bez.kontakt_a_id not in org_map and bez.kontakt_b and bez.kontakt_b.typ == "organisation":
                org_map[bez.kontakt_a_id] = bez.kontakt_b

    return templates.TemplateResponse("pages/kontakte/liste.html", {
        "request": request,
        "user": user,
        "active_page": "kontakte",
        "ergebnis": ergebnis,
        "gruppen": gruppen,
        "buchstabe": buchstabe,
        "sortierung": sortierung,
        "gruppe_id": gruppe_id,
        "org_map": org_map,
        "q": q,
        "ort_filter": ort or "",
        "email_filter": email or "",
        "position_filter": position or "",
        "betreuer_filter": betreuer or "",
        "eigentuemer_filter": eigentuemer or "",
        "org_name_filter": org_name or "",
    })


@router.get("/neu", response_class=HTMLResponse)
async def neu_formular(request: Request, user=Depends(get_current_user)):
    return templates.TemplateResponse("pages/kontakte/formular.html", {
        "request": request,
        "user": user,
        "active_page": "kontakte",
        "kontakt": None,
        "typ": "person",
    })


@router.post("/neu")
async def erstellen(
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    daten = {k: v for k, v in form.items() if v and k not in ("typ", "blacklist_override")}
    daten["typ"] = form.get("typ", "person")

    # Blacklist-Check (ausser bei Override)
    if not form.get("blacklist_override"):
        treffer = kontakt_service.blacklist_check(db, daten)
        if treffer:
            return templates.TemplateResponse("pages/kontakte/formular.html", {
                "request": request,
                "user": user,
                "active_page": "kontakte" if daten["typ"] == "person" else "organisationen",
                "kontakt": None,
                "typ": daten["typ"],
                "blacklist_warnung": treffer,
                "formular_daten": daten,
            })

    kontakt = kontakt_service.erstellen(db, daten, erstellt_von=user.kuerzel)
    return RedirectResponse(url=f"/kontakte/{kontakt.id}", status_code=303)


@router.get("/{kontakt_id}", response_class=HTMLResponse)
async def detail(kontakt_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakt = kontakt_service.detail(db, kontakt_id)
    if not kontakt:
        return RedirectResponse(url="/kontakte", status_code=303)

    alle_kontakte = db.query(Kontakt).filter(Kontakt.ist_blacklisted == False).order_by(Kontakt.nachname, Kontakt.firmenname).all()
    alle_gruppen = db.query(Gruppe).order_by(Gruppe.name).all()
    zugeordnete_gruppen_ids = {kg.gruppe_id for kg in kontakt.gruppen}
    kategorien = db.query(TagKategorie).order_by(TagKategorie.sortierung, TagKategorie.name).all()
    alle_branchen = db.query(Branche).order_by(Branche.sortierung, Branche.name).all()
    zugeordnete_branchen_ids = {kb.branche_id for kb in kontakt.branchen}

    return templates.TemplateResponse("pages/kontakte/detail.html", {
        "request": request,
        "user": user,
        "active_page": "kontakte" if kontakt.typ == "person" else "organisationen",
        "kontakt": kontakt,
        "alle_kontakte": alle_kontakte,
        "alle_gruppen": alle_gruppen,
        "zugeordnete_gruppen_ids": zugeordnete_gruppen_ids,
        "kategorien": kategorien,
        "alle_branchen": alle_branchen,
        "zugeordnete_branchen_ids": zugeordnete_branchen_ids,
    })


@router.get("/{kontakt_id}/bearbeiten", response_class=HTMLResponse)
async def bearbeiten_formular(kontakt_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakt = kontakt_service.detail(db, kontakt_id)
    if not kontakt:
        return RedirectResponse(url="/kontakte", status_code=303)

    alle_kontakte = db.query(Kontakt).filter(Kontakt.ist_blacklisted == False).order_by(Kontakt.nachname, Kontakt.firmenname).all()
    alle_gruppen = db.query(Gruppe).order_by(Gruppe.name).all()
    zugeordnete_gruppen_ids = {kg.gruppe_id for kg in kontakt.gruppen}
    kategorien = db.query(TagKategorie).order_by(TagKategorie.sortierung, TagKategorie.name).all()
    alle_branchen = db.query(Branche).order_by(Branche.sortierung, Branche.name).all()
    zugeordnete_branchen_ids = {kb.branche_id for kb in kontakt.branchen}

    return templates.TemplateResponse("pages/kontakte/formular.html", {
        "request": request,
        "user": user,
        "active_page": "kontakte" if kontakt.typ == "person" else "organisationen",
        "kontakt": kontakt,
        "typ": kontakt.typ,
        "alle_kontakte": alle_kontakte,
        "alle_gruppen": alle_gruppen,
        "zugeordnete_gruppen_ids": zugeordnete_gruppen_ids,
        "kategorien": kategorien,
        "alle_branchen": alle_branchen,
        "zugeordnete_branchen_ids": zugeordnete_branchen_ids,
    })


@router.post("/{kontakt_id}/bearbeiten")
async def aktualisieren(kontakt_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    form = await request.form()
    daten = {k: v if v else None for k, v in form.items() if k not in ("typ", "ist_blacklisted", "newsletter", "keine_mails", "keine_briefe", "keine_anrufe")}

    # Kommunikations-Praeferenzen (Checkboxen)
    daten["newsletter"] = form.get("newsletter") == "1"
    daten["keine_mails"] = form.get("keine_mails") == "1"
    daten["keine_briefe"] = form.get("keine_briefe") == "1"
    daten["keine_anrufe"] = form.get("keine_anrufe") == "1"

    # Blacklist-Status auswerten
    kontakt = kontakt_service.detail(db, kontakt_id)
    war_blacklisted = kontakt.ist_blacklisted if kontakt else False
    ist_blacklisted = form.get("ist_blacklisted") == "1"

    if ist_blacklisted and not war_blacklisted:
        daten["ist_blacklisted"] = True
        daten["blacklist_am"] = datetime.now()
        daten["blacklist_von"] = user.kuerzel
    elif not ist_blacklisted and war_blacklisted:
        daten["ist_blacklisted"] = False
        daten["blacklist_grund"] = None
        daten["blacklist_am"] = None
        daten["blacklist_von"] = None

    kontakt_service.aktualisieren(db, kontakt_id, daten, aktualisiert_von=user.kuerzel)
    return RedirectResponse(url=f"/kontakte/{kontakt_id}", status_code=303)


@router.get("/{kontakt_id}/loeschen")
async def loeschen(kontakt_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakt = kontakt_service.detail(db, kontakt_id)
    typ = kontakt.typ if kontakt else "person"
    kontakt_service.loeschen(db, kontakt_id)
    return RedirectResponse(url="/kontakte" if typ == "person" else "/organisationen", status_code=303)


@router.post("/{kontakt_id}/tags/{tag_id}/toggle", response_class=HTMLResponse)
async def tag_toggle(kontakt_id: int, tag_id: int, request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakt_service.tag_toggle(db, kontakt_id, tag_id)
    kontakt = kontakt_service.detail(db, kontakt_id)
    kategorien = db.query(TagKategorie).order_by(TagKategorie.sortierung, TagKategorie.name).all()
    return templates.TemplateResponse("components/tag_chips.html", {
        "request": request,
        "kontakt_tags": kontakt.tags,
        "editable": True,
        "kontakt_id": kontakt_id,
        "kategorien": kategorien,
    })


@router.post("/{kontakt_id}/branchen/{branche_id}/toggle", response_class=HTMLResponse)
async def branche_toggle(
    kontakt_id: int,
    branche_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    existing = db.query(KontaktBranche).filter(
        KontaktBranche.kontakt_id == kontakt_id,
        KontaktBranche.branche_id == branche_id,
    ).first()

    if existing:
        db.delete(existing)
    else:
        db.add(KontaktBranche(kontakt_id=kontakt_id, branche_id=branche_id))
    db.commit()

    alle_branchen = db.query(Branche).order_by(Branche.sortierung, Branche.name).all()
    zugeordnete = db.query(KontaktBranche.branche_id).filter(KontaktBranche.kontakt_id == kontakt_id).all()
    zugeordnete_ids = {b[0] for b in zugeordnete}

    return templates.TemplateResponse("components/branchen_toggle.html", {
        "request": request,
        "alle_branchen": alle_branchen,
        "zugeordnete_branchen_ids": zugeordnete_ids,
        "kontakt_id": kontakt_id,
        "editable": True,
    })


@router.get("/export", response_class=HTMLResponse)
async def export(format: str = "csv", user=Depends(get_current_user), db: Session = Depends(get_db)):
    if format == "excel":
        data = export_service.kontakte_excel(db, typ="person")
        return StreamingResponse(
            iter([data]),
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={"Content-Disposition": "attachment; filename=kontakte.xlsx"},
        )
    else:
        data = export_service.kontakte_csv(db, typ="person")
        return StreamingResponse(
            iter([data.encode("utf-8-sig")]),
            media_type="text/csv",
            headers={"Content-Disposition": "attachment; filename=kontakte.csv"},
        )


# --- Beziehungen CRUD ---

@router.post("/{kontakt_id}/beziehungen", response_class=HTMLResponse)
async def beziehung_erstellen(
    kontakt_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    form = await request.form()
    partner_id = int(form["partner_id"])
    typ = form.get("typ", "kennt")

    # Rollen je nach Typ setzen (A = Person, B = Org – immer konsistent)
    rollen = {
        "mitarbeiter_von": ("Mitarbeiter", "Arbeitgeber"),
        "vorstand_von": ("Vorstand", "Organisation"),
        "mitglied_von": ("Mitglied", "Organisation"),
        "kennt": ("Kontakt", "Kontakt"),
        "partner_von": ("Partner", "Partner"),
        "sonstiges": (None, None),
    }
    rolle_a, rolle_b = rollen.get(typ, (None, None))

    # Person immer als kontakt_a, Org immer als kontakt_b speichern
    kontakt = db.query(Kontakt).filter(Kontakt.id == kontakt_id).first()
    if kontakt and kontakt.typ == "organisation" and typ in ("mitarbeiter_von", "vorstand_von", "mitglied_von"):
        # Org erstellt Beziehung zu Person: Person=A, Org=B
        a_id, b_id = partner_id, kontakt_id
    else:
        a_id, b_id = kontakt_id, partner_id

    bez = Beziehung(
        kontakt_a_id=a_id,
        kontakt_b_id=b_id,
        typ=typ,
        rolle_a=rolle_a,
        rolle_b=rolle_b,
        ist_aktiv=True,
    )
    db.add(bez)
    db.commit()

    return _render_beziehungen(db, kontakt_id, request)


@router.delete("/{kontakt_id}/beziehungen/{bez_id}", response_class=HTMLResponse)
async def beziehung_loeschen(
    kontakt_id: int,
    bez_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    bez = db.query(Beziehung).filter(Beziehung.id == bez_id).first()
    if bez:
        db.delete(bez)
        db.commit()

    return _render_beziehungen(db, kontakt_id, request)


def _render_beziehungen(db: Session, kontakt_id: int, request: Request):
    kontakt = kontakt_service.detail(db, kontakt_id)
    alle_kontakte = db.query(Kontakt).filter(Kontakt.ist_blacklisted == False).order_by(Kontakt.nachname, Kontakt.firmenname).all()
    return templates.TemplateResponse("components/beziehungen.html", {
        "request": request,
        "beziehungen": kontakt.alle_beziehungen,
        "kontakt_id": kontakt_id,
        "alle_kontakte": alle_kontakte,
        "kontakt_typ": kontakt.typ,
    })


# --- Gruppen Toggle ---

@router.post("/{kontakt_id}/gruppen/{gruppe_id}/toggle", response_class=HTMLResponse)
async def gruppen_toggle(
    kontakt_id: int,
    gruppe_id: int,
    request: Request,
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    existing = db.query(KontaktGruppe).filter(
        KontaktGruppe.kontakt_id == kontakt_id,
        KontaktGruppe.gruppe_id == gruppe_id,
    ).first()

    if existing:
        db.delete(existing)
    else:
        db.add(KontaktGruppe(kontakt_id=kontakt_id, gruppe_id=gruppe_id))
    db.commit()

    alle_gruppen = db.query(Gruppe).order_by(Gruppe.name).all()
    zugeordnete = db.query(KontaktGruppe.gruppe_id).filter(KontaktGruppe.kontakt_id == kontakt_id).all()
    zugeordnete_ids = {g[0] for g in zugeordnete}

    return templates.TemplateResponse("components/gruppen_toggle.html", {
        "request": request,
        "alle_gruppen": alle_gruppen,
        "zugeordnete_gruppen_ids": zugeordnete_ids,
        "kontakt_id": kontakt_id,
    })
