"""
BreakPilot Messenger API

Stellt Endpoints fuer:
- Kontaktverwaltung (CRUD)
- Konversationen
- Nachrichten
- CSV-Import fuer Kontakte
- Gruppenmanagement

DSGVO-konform: Alle Daten werden lokal gespeichert.
"""

import os
import csv
import uuid
import json
from io import StringIO
from datetime import datetime
from typing import List, Optional, Dict, Any
from pathlib import Path

from fastapi import APIRouter, HTTPException, UploadFile, File, Query
from pydantic import BaseModel, Field

router = APIRouter(prefix="/api/messenger", tags=["Messenger"])

# Datenspeicherung (JSON-basiert fuer einfache Persistenz)
DATA_DIR = Path(__file__).parent / "data" / "messenger"
DATA_DIR.mkdir(parents=True, exist_ok=True)

CONTACTS_FILE = DATA_DIR / "contacts.json"
CONVERSATIONS_FILE = DATA_DIR / "conversations.json"
MESSAGES_FILE = DATA_DIR / "messages.json"
GROUPS_FILE = DATA_DIR / "groups.json"


# ==========================================
# PYDANTIC MODELS
# ==========================================

class ContactBase(BaseModel):
    """Basis-Modell fuer Kontakte."""
    name: str = Field(..., min_length=1, max_length=200)
    email: Optional[str] = None
    phone: Optional[str] = None
    role: str = Field(default="parent", description="parent, teacher, staff, student")
    student_name: Optional[str] = Field(None, description="Name des zugehoerigen Schuelers")
    class_name: Optional[str] = Field(None, description="Klasse z.B. 10a")
    notes: Optional[str] = None
    tags: List[str] = Field(default_factory=list)
    matrix_id: Optional[str] = Field(None, description="Matrix-ID z.B. @user:matrix.org")
    preferred_channel: str = Field(default="email", description="email, matrix, pwa")


class ContactCreate(ContactBase):
    """Model fuer neuen Kontakt."""
    pass


class Contact(ContactBase):
    """Vollstaendiger Kontakt mit ID."""
    id: str
    created_at: str
    updated_at: str
    online: bool = False
    last_seen: Optional[str] = None


class ContactUpdate(BaseModel):
    """Update-Model fuer Kontakte."""
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    role: Optional[str] = None
    student_name: Optional[str] = None
    class_name: Optional[str] = None
    notes: Optional[str] = None
    tags: Optional[List[str]] = None
    matrix_id: Optional[str] = None
    preferred_channel: Optional[str] = None


class GroupBase(BaseModel):
    """Basis-Modell fuer Gruppen."""
    name: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = None
    group_type: str = Field(default="class", description="class, department, custom")


class GroupCreate(GroupBase):
    """Model fuer neue Gruppe."""
    member_ids: List[str] = Field(default_factory=list)


class Group(GroupBase):
    """Vollstaendige Gruppe mit ID."""
    id: str
    member_ids: List[str] = []
    created_at: str
    updated_at: str


class MessageBase(BaseModel):
    """Basis-Modell fuer Nachrichten."""
    content: str = Field(..., min_length=1)
    content_type: str = Field(default="text", description="text, file, image")
    file_url: Optional[str] = None
    send_email: bool = Field(default=False, description="Nachricht auch per Email senden")


class MessageCreate(MessageBase):
    """Model fuer neue Nachricht."""
    conversation_id: str


class Message(MessageBase):
    """Vollstaendige Nachricht mit ID."""
    id: str
    conversation_id: str
    sender_id: str  # "self" fuer eigene Nachrichten
    timestamp: str
    read: bool = False
    read_at: Optional[str] = None
    email_sent: bool = False
    email_sent_at: Optional[str] = None
    email_error: Optional[str] = None


class ConversationBase(BaseModel):
    """Basis-Modell fuer Konversationen."""
    name: Optional[str] = None
    is_group: bool = False


class Conversation(ConversationBase):
    """Vollstaendige Konversation mit ID."""
    id: str
    participant_ids: List[str] = []
    group_id: Optional[str] = None
    created_at: str
    updated_at: str
    last_message: Optional[str] = None
    last_message_time: Optional[str] = None
    unread_count: int = 0


class CSVImportResult(BaseModel):
    """Ergebnis eines CSV-Imports."""
    imported: int
    skipped: int
    errors: List[str]
    contacts: List[Contact]


# ==========================================
# DATA HELPERS
# ==========================================

def load_json(filepath: Path) -> List[Dict]:
    """Laedt JSON-Daten aus Datei."""
    if not filepath.exists():
        return []
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return []


def save_json(filepath: Path, data: List[Dict]):
    """Speichert Daten in JSON-Datei."""
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def get_contacts() -> List[Dict]:
    return load_json(CONTACTS_FILE)


def save_contacts(contacts: List[Dict]):
    save_json(CONTACTS_FILE, contacts)


def get_conversations() -> List[Dict]:
    return load_json(CONVERSATIONS_FILE)


def save_conversations(conversations: List[Dict]):
    save_json(CONVERSATIONS_FILE, conversations)


def get_messages() -> List[Dict]:
    return load_json(MESSAGES_FILE)


def save_messages(messages: List[Dict]):
    save_json(MESSAGES_FILE, messages)


def get_groups() -> List[Dict]:
    return load_json(GROUPS_FILE)


def save_groups(groups: List[Dict]):
    save_json(GROUPS_FILE, groups)


# ==========================================
# 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."""
    from fastapi.responses import StreamingResponse

    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"}
    )


# ==========================================
# GROUPS ENDPOINTS
# ==========================================

@router.get("/groups", response_model=List[Group])
async def list_groups():
    """Listet alle Gruppen auf."""
    return get_groups()


@router.post("/groups", response_model=Group)
async def create_group(group: GroupCreate):
    """Erstellt eine neue Gruppe."""
    groups = get_groups()

    now = datetime.utcnow().isoformat()
    new_group = {
        "id": str(uuid.uuid4()),
        "created_at": now,
        "updated_at": now,
        **group.dict()
    }

    groups.append(new_group)
    save_groups(groups)

    return new_group


@router.put("/groups/{group_id}/members")
async def update_group_members(group_id: str, member_ids: List[str]):
    """Aktualisiert die Mitglieder einer Gruppe."""
    groups = get_groups()
    group_idx = next((i for i, g in enumerate(groups) if g["id"] == group_id), None)

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

    groups[group_idx]["member_ids"] = member_ids
    groups[group_idx]["updated_at"] = datetime.utcnow().isoformat()

    save_groups(groups)
    return groups[group_idx]


@router.delete("/groups/{group_id}")
async def delete_group(group_id: str):
    """Loescht eine Gruppe."""
    groups = get_groups()
    groups = [g for g in groups if g["id"] != group_id]
    save_groups(groups)

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


# ==========================================
# CONVERSATIONS ENDPOINTS
# ==========================================

@router.get("/conversations", response_model=List[Conversation])
async def list_conversations():
    """Listet alle Konversationen auf."""
    conversations = get_conversations()
    messages = get_messages()

    # Unread count und letzte Nachricht hinzufuegen
    for conv in conversations:
        conv_messages = [m for m in messages if m.get("conversation_id") == conv["id"]]
        conv["unread_count"] = len([m for m in conv_messages if not m.get("read") and m.get("sender_id") != "self"])

        if conv_messages:
            last_msg = max(conv_messages, key=lambda m: m.get("timestamp", ""))
            conv["last_message"] = last_msg.get("content", "")[:50]
            conv["last_message_time"] = last_msg.get("timestamp")

    # Nach letzter Nachricht sortieren
    conversations.sort(key=lambda c: c.get("last_message_time") or "", reverse=True)

    return conversations


@router.post("/conversations", response_model=Conversation)
async def create_conversation(contact_id: Optional[str] = None, group_id: Optional[str] = None):
    """
    Erstellt eine neue Konversation.
    Entweder mit einem Kontakt (1:1) oder einer Gruppe.
    """
    conversations = get_conversations()

    if not contact_id and not group_id:
        raise HTTPException(status_code=400, detail="Entweder contact_id oder group_id erforderlich")

    # Pruefen ob Konversation bereits existiert
    if contact_id:
        existing = next((c for c in conversations
                        if not c.get("is_group") and contact_id in c.get("participant_ids", [])), None)
        if existing:
            return existing

    now = datetime.utcnow().isoformat()

    if group_id:
        groups = get_groups()
        group = next((g for g in groups if g["id"] == group_id), None)
        if not group:
            raise HTTPException(status_code=404, detail="Gruppe nicht gefunden")

        new_conv = {
            "id": str(uuid.uuid4()),
            "name": group.get("name"),
            "is_group": True,
            "participant_ids": group.get("member_ids", []),
            "group_id": group_id,
            "created_at": now,
            "updated_at": now,
            "last_message": None,
            "last_message_time": None,
            "unread_count": 0
        }
    else:
        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")

        new_conv = {
            "id": str(uuid.uuid4()),
            "name": contact.get("name"),
            "is_group": False,
            "participant_ids": [contact_id],
            "group_id": None,
            "created_at": now,
            "updated_at": now,
            "last_message": None,
            "last_message_time": None,
            "unread_count": 0
        }

    conversations.append(new_conv)
    save_conversations(conversations)

    return new_conv


@router.get("/conversations/{conversation_id}", response_model=Conversation)
async def get_conversation(conversation_id: str):
    """Ruft eine Konversation ab."""
    conversations = get_conversations()
    conv = next((c for c in conversations if c["id"] == conversation_id), None)

    if not conv:
        raise HTTPException(status_code=404, detail="Konversation nicht gefunden")

    return conv


@router.delete("/conversations/{conversation_id}")
async def delete_conversation(conversation_id: str):
    """Loescht eine Konversation und alle zugehoerigen Nachrichten."""
    conversations = get_conversations()
    conversations = [c for c in conversations if c["id"] != conversation_id]
    save_conversations(conversations)

    messages = get_messages()
    messages = [m for m in messages if m.get("conversation_id") != conversation_id]
    save_messages(messages)

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


# ==========================================
# MESSAGES ENDPOINTS
# ==========================================

@router.get("/conversations/{conversation_id}/messages", response_model=List[Message])
async def list_messages(
    conversation_id: str,
    limit: int = Query(50, ge=1, le=200),
    before: Optional[str] = Query(None, description="Load messages before this timestamp")
):
    """Ruft Nachrichten einer Konversation ab."""
    messages = get_messages()
    conv_messages = [m for m in messages if m.get("conversation_id") == conversation_id]

    if before:
        conv_messages = [m for m in conv_messages if m.get("timestamp", "") < before]

    # Nach Zeit sortieren (neueste zuletzt)
    conv_messages.sort(key=lambda m: m.get("timestamp", ""))

    return conv_messages[-limit:]


@router.post("/conversations/{conversation_id}/messages", response_model=Message)
async def send_message(conversation_id: str, message: MessageBase):
    """
    Sendet eine Nachricht in einer Konversation.

    Wenn send_email=True und der Kontakt eine Email-Adresse hat,
    wird die Nachricht auch per Email versendet.
    """
    conversations = get_conversations()
    conv = next((c for c in conversations if c["id"] == conversation_id), None)

    if not conv:
        raise HTTPException(status_code=404, detail="Konversation nicht gefunden")

    now = datetime.utcnow().isoformat()

    new_message = {
        "id": str(uuid.uuid4()),
        "conversation_id": conversation_id,
        "sender_id": "self",
        "timestamp": now,
        "read": True,
        "read_at": now,
        "email_sent": False,
        "email_sent_at": None,
        "email_error": None,
        **message.dict()
    }

    # Email-Versand wenn gewuenscht
    if message.send_email and not conv.get("is_group"):
        # Kontakt laden
        participant_ids = conv.get("participant_ids", [])
        if participant_ids:
            contacts = get_contacts()
            contact = next((c for c in contacts if c["id"] == participant_ids[0]), None)

            if contact and contact.get("email"):
                try:
                    from email_service import email_service

                    result = email_service.send_messenger_notification(
                        to_email=contact["email"],
                        to_name=contact.get("name", ""),
                        sender_name="BreakPilot Lehrer",  # TODO: Aktuellen User-Namen verwenden
                        message_content=message.content
                    )

                    if result.success:
                        new_message["email_sent"] = True
                        new_message["email_sent_at"] = result.sent_at
                    else:
                        new_message["email_error"] = result.error

                except Exception as e:
                    new_message["email_error"] = str(e)

    messages = get_messages()
    messages.append(new_message)
    save_messages(messages)

    # Konversation aktualisieren
    conv_idx = next(i for i, c in enumerate(conversations) if c["id"] == conversation_id)
    conversations[conv_idx]["last_message"] = message.content[:50]
    conversations[conv_idx]["last_message_time"] = now
    conversations[conv_idx]["updated_at"] = now
    save_conversations(conversations)

    return new_message


@router.put("/messages/{message_id}/read")
async def mark_message_read(message_id: str):
    """Markiert eine Nachricht als gelesen."""
    messages = get_messages()
    msg_idx = next((i for i, m in enumerate(messages) if m["id"] == message_id), None)

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

    messages[msg_idx]["read"] = True
    messages[msg_idx]["read_at"] = datetime.utcnow().isoformat()
    save_messages(messages)

    return {"status": "read", "id": message_id}


@router.put("/conversations/{conversation_id}/read-all")
async def mark_all_messages_read(conversation_id: str):
    """Markiert alle Nachrichten einer Konversation als gelesen."""
    messages = get_messages()
    now = datetime.utcnow().isoformat()

    for msg in messages:
        if msg.get("conversation_id") == conversation_id and not msg.get("read"):
            msg["read"] = True
            msg["read_at"] = now

    save_messages(messages)

    return {"status": "all_read", "conversation_id": conversation_id}


# ==========================================
# TEMPLATES ENDPOINTS
# ==========================================

DEFAULT_TEMPLATES = [
    {
        "id": "1",
        "name": "Terminbestaetigung",
        "content": "Vielen Dank fuer Ihre Terminanfrage. Ich bestaetige den Termin am [DATUM] um [UHRZEIT]. Bitte geben Sie mir Bescheid, falls sich etwas aendern sollte.",
        "category": "termin"
    },
    {
        "id": "2",
        "name": "Hausaufgaben-Info",
        "content": "Zur Information: Die Hausaufgaben fuer diese Woche umfassen [THEMA]. Abgabetermin ist [DATUM]. Bei Fragen stehe ich gerne zur Verfuegung.",
        "category": "hausaufgaben"
    },
    {
        "id": "3",
        "name": "Entschuldigung bestaetigen",
        "content": "Ich bestaetige den Erhalt der Entschuldigung fuer [NAME] am [DATUM]. Die Fehlzeiten wurden entsprechend vermerkt.",
        "category": "entschuldigung"
    },
    {
        "id": "4",
        "name": "Gespraechsanfrage",
        "content": "Ich wuerde gerne einen Termin fuer ein Gespraech mit Ihnen vereinbaren, um [THEMA] zu besprechen. Waeren Sie am [DATUM] um [UHRZEIT] verfuegbar?",
        "category": "gespraech"
    },
    {
        "id": "5",
        "name": "Krankmeldung bestaetigen",
        "content": "Vielen Dank fuer Ihre Krankmeldung fuer [NAME]. Ich wuensche gute Besserung. Bitte reichen Sie eine schriftliche Entschuldigung nach, sobald Ihr Kind wieder gesund ist.",
        "category": "krankmeldung"
    }
]


@router.get("/templates")
async def list_templates():
    """Listet alle Nachrichtenvorlagen auf."""
    templates_file = DATA_DIR / "templates.json"
    if templates_file.exists():
        templates = load_json(templates_file)
    else:
        templates = DEFAULT_TEMPLATES
        save_json(templates_file, templates)

    return templates


@router.post("/templates")
async def create_template(name: str, content: str, category: str = "custom"):
    """Erstellt eine neue Vorlage."""
    templates_file = DATA_DIR / "templates.json"
    templates = load_json(templates_file) if templates_file.exists() else DEFAULT_TEMPLATES.copy()

    new_template = {
        "id": str(uuid.uuid4()),
        "name": name,
        "content": content,
        "category": category
    }

    templates.append(new_template)
    save_json(templates_file, templates)

    return new_template


@router.delete("/templates/{template_id}")
async def delete_template(template_id: str):
    """Loescht eine Vorlage."""
    templates_file = DATA_DIR / "templates.json"
    templates = load_json(templates_file) if templates_file.exists() else DEFAULT_TEMPLATES.copy()

    templates = [t for t in templates if t["id"] != template_id]
    save_json(templates_file, templates)

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


# ==========================================
# STATS ENDPOINT
# ==========================================

@router.get("/stats")
async def get_messenger_stats():
    """Gibt Statistiken zum Messenger zurueck."""
    contacts = get_contacts()
    conversations = get_conversations()
    messages = get_messages()
    groups = get_groups()

    unread_total = sum(1 for m in messages if not m.get("read") and m.get("sender_id") != "self")

    return {
        "total_contacts": len(contacts),
        "total_groups": len(groups),
        "total_conversations": len(conversations),
        "total_messages": len(messages),
        "unread_messages": unread_total,
        "contacts_by_role": {
            role: len([c for c in contacts if c.get("role") == role])
            for role in set(c.get("role", "parent") for c in contacts)
        }
    }
