"""
Messenger API - Contact Routes.

CRUD, CSV import/export for contacts.
"""

import csv
import uuid
from io import StringIO
from datetime import datetime
from typing import List, Optional

from fastapi import APIRouter, HTTPException, UploadFile, File, Query
from fastapi.responses import StreamingResponse

from .models import (
    Contact,
    ContactCreate,
    ContactUpdate,
    CSVImportResult,
)
from .helpers import get_contacts, save_contacts

router = APIRouter(tags=["Messenger"])


# ==========================================
# CONTACTS ENDPOINTS
# ==========================================

@router.get("/contacts", response_model=List[Contact])
async def list_contacts(
    role: Optional[str] = Query(None, description="Filter by role"),
    class_name: Optional[str] = Query(None, description="Filter by class"),
    search: Optional[str] = Query(None, description="Search in name/email")
):
    """Listet alle Kontakte auf."""
    contacts = get_contacts()

    # Filter anwenden
    if role:
        contacts = [c for c in contacts if c.get("role") == role]
    if class_name:
        contacts = [c for c in contacts if c.get("class_name") == class_name]
    if search:
        search_lower = search.lower()
        contacts = [c for c in contacts if
                   search_lower in c.get("name", "").lower() or
                   search_lower in (c.get("email") or "").lower() or
                   search_lower in (c.get("student_name") or "").lower()]

    return contacts


@router.post("/contacts", response_model=Contact)
async def create_contact(contact: ContactCreate):
    """Erstellt einen neuen Kontakt."""
    contacts = get_contacts()

    # Pruefen ob Email bereits existiert
    if contact.email:
        existing = [c for c in contacts if c.get("email") == contact.email]
        if existing:
            raise HTTPException(status_code=400, detail="Kontakt mit dieser Email existiert bereits")

    now = datetime.utcnow().isoformat()
    new_contact = {
        "id": str(uuid.uuid4()),
        "created_at": now,
        "updated_at": now,
        "online": False,
        "last_seen": None,
        **contact.dict()
    }

    contacts.append(new_contact)
    save_contacts(contacts)

    return new_contact


@router.get("/contacts/{contact_id}", response_model=Contact)
async def get_contact(contact_id: str):
    """Ruft einen einzelnen Kontakt ab."""
    contacts = get_contacts()
    contact = next((c for c in contacts if c["id"] == contact_id), None)

    if not contact:
        raise HTTPException(status_code=404, detail="Kontakt nicht gefunden")

    return contact


@router.put("/contacts/{contact_id}", response_model=Contact)
async def update_contact(contact_id: str, update: ContactUpdate):
    """Aktualisiert einen Kontakt."""
    contacts = get_contacts()
    contact_idx = next((i for i, c in enumerate(contacts) if c["id"] == contact_id), None)

    if contact_idx is None:
        raise HTTPException(status_code=404, detail="Kontakt nicht gefunden")

    update_data = update.dict(exclude_unset=True)
    contacts[contact_idx].update(update_data)
    contacts[contact_idx]["updated_at"] = datetime.utcnow().isoformat()

    save_contacts(contacts)
    return contacts[contact_idx]


@router.delete("/contacts/{contact_id}")
async def delete_contact(contact_id: str):
    """Loescht einen Kontakt."""
    contacts = get_contacts()
    contacts = [c for c in contacts if c["id"] != contact_id]
    save_contacts(contacts)

    return {"status": "deleted", "id": contact_id}


@router.post("/contacts/import", response_model=CSVImportResult)
async def import_contacts_csv(file: UploadFile = File(...)):
    """
    Importiert Kontakte aus einer CSV-Datei.

    Erwartete Spalten:
    - name (required)
    - email
    - phone
    - role (parent/teacher/staff/student)
    - student_name
    - class_name
    - notes
    - tags (komma-separiert)
    """
    if not file.filename.endswith('.csv'):
        raise HTTPException(status_code=400, detail="Nur CSV-Dateien werden unterstuetzt")

    content = await file.read()
    try:
        text = content.decode('utf-8')
    except UnicodeDecodeError:
        text = content.decode('latin-1')

    contacts = get_contacts()
    existing_emails = {c.get("email") for c in contacts if c.get("email")}

    imported = []
    skipped = 0
    errors = []

    reader = csv.DictReader(StringIO(text), delimiter=';')  # Deutsche CSV meist mit Semikolon
    if not reader.fieldnames or 'name' not in [f.lower() for f in reader.fieldnames]:
        # Versuche mit Komma
        reader = csv.DictReader(StringIO(text), delimiter=',')

    for row_num, row in enumerate(reader, start=2):
        try:
            # Normalisiere Spaltennamen
            row = {k.lower().strip(): v.strip() if v else "" for k, v in row.items()}

            name = row.get('name') or row.get('kontakt') or row.get('elternname')
            if not name:
                errors.append(f"Zeile {row_num}: Name fehlt")
                skipped += 1
                continue

            email = row.get('email') or row.get('e-mail') or row.get('mail')
            if email and email in existing_emails:
                errors.append(f"Zeile {row_num}: Email {email} existiert bereits")
                skipped += 1
                continue

            now = datetime.utcnow().isoformat()
            tags_str = row.get('tags') or row.get('kategorien') or ""
            tags = [t.strip() for t in tags_str.split(',') if t.strip()]

            # Matrix-ID und preferred_channel auslesen
            matrix_id = row.get('matrix_id') or row.get('matrix') or None
            preferred_channel = row.get('preferred_channel') or row.get('kanal') or "email"
            if preferred_channel not in ["email", "matrix", "pwa"]:
                preferred_channel = "email"

            new_contact = {
                "id": str(uuid.uuid4()),
                "name": name,
                "email": email if email else None,
                "phone": row.get('phone') or row.get('telefon') or row.get('tel'),
                "role": row.get('role') or row.get('rolle') or "parent",
                "student_name": row.get('student_name') or row.get('schueler') or row.get('kind'),
                "class_name": row.get('class_name') or row.get('klasse'),
                "notes": row.get('notes') or row.get('notizen') or row.get('bemerkungen'),
                "tags": tags,
                "matrix_id": matrix_id if matrix_id else None,
                "preferred_channel": preferred_channel,
                "created_at": now,
                "updated_at": now,
                "online": False,
                "last_seen": None
            }

            contacts.append(new_contact)
            imported.append(new_contact)
            if email:
                existing_emails.add(email)

        except Exception as e:
            errors.append(f"Zeile {row_num}: {str(e)}")
            skipped += 1

    save_contacts(contacts)

    return CSVImportResult(
        imported=len(imported),
        skipped=skipped,
        errors=errors[:20],  # Maximal 20 Fehler zurueckgeben
        contacts=imported
    )


@router.get("/contacts/export/csv")
async def export_contacts_csv():
    """Exportiert alle Kontakte als CSV."""
    contacts = get_contacts()

    output = StringIO()
    fieldnames = ['name', 'email', 'phone', 'role', 'student_name', 'class_name', 'notes', 'tags', 'matrix_id', 'preferred_channel']
    writer = csv.DictWriter(output, fieldnames=fieldnames, delimiter=';')
    writer.writeheader()

    for contact in contacts:
        writer.writerow({
            'name': contact.get('name', ''),
            'email': contact.get('email', ''),
            'phone': contact.get('phone', ''),
            'role': contact.get('role', ''),
            'student_name': contact.get('student_name', ''),
            'class_name': contact.get('class_name', ''),
            'notes': contact.get('notes', ''),
            'tags': ','.join(contact.get('tags', [])),
            'matrix_id': contact.get('matrix_id', ''),
            'preferred_channel': contact.get('preferred_channel', 'email')
        })

    output.seek(0)

    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition": "attachment; filename=kontakte.csv"}
    )
