"""AI Tools for the Tool Registry — context-aware tools registered
by the ai_proactive plugin for use by the AI Assistant.

Each tool is an async function (arguments: dict, context: dict) -> str
that performs SQL queries and returns JSON-string results.
"""

from __future__ import annotations

import json
import logging
import uuid
from typing import Any

from sqlalchemy import select, text
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.db import create_db_session
from app.models.audit import AuditLog
from app.models.contact import Contact
from app.plugins.builtins.mail.models import Mail

logger = logging.getLogger(__name__)


def _serialize(row: Any) -> dict[str, Any]:
    """Serialize a SQLAlchemy model instance to a dict."""
    if row is None:
        return {}
    result: dict[str, Any] = {}
    for column in row.__table__.columns:
        val = getattr(row, column.name)
        if hasattr(val, "isoformat"):
            result[column.name] = val.isoformat()
        elif isinstance(val, uuid.UUID):
            result[column.name] = str(val)
        else:
            result[column.name] = val
    return result


async def _get_db_and_tenant(context: dict[str, Any]) -> tuple[AsyncSession, uuid.UUID, uuid.UUID]:
    """Extract tenant_id, user_id from context and create a DB session."""
    tenant_id = uuid.UUID(context.get("tenant_id", ""))
    user_id = uuid.UUID(context.get("user_id", ""))
    db = context.get("db")
    if db is not None and isinstance(db, AsyncSession):
        return db, tenant_id, user_id
    # Fallback: create standalone session
    raise RuntimeError("No db session in context")


# ─── Tool Handlers ───


async def get_contact_mails_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Get all mails for a contact, ordered by received_at DESC."""
    try:
        db, tenant_id, _ = await _get_db_and_tenant(context)
        contact_id = uuid.UUID(arguments["contact_id"])
        limit = arguments.get("limit", 10)
        result = await db.execute(
            select(Mail)
            .where(Mail.contact_id == contact_id)
            .where(Mail.tenant_id == tenant_id)
            .order_by(Mail.received_at.desc())
            .limit(limit)
        )
        mails = [_serialize(m) for m in result.scalars().all()]
        return json.dumps({"mails": mails, "count": len(mails)}, default=str)
    except Exception as e:
        logger.exception("get_contact_mails_handler failed")
        return json.dumps({"error": str(e)})


async def get_contact_history_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Get audit log history for an entity, ordered by timestamp DESC."""
    try:
        db, tenant_id, _ = await _get_db_and_tenant(context)
        entity_id = uuid.UUID(arguments["entity_id"])
        limit = arguments.get("limit", 20)
        result = await db.execute(
            select(AuditLog)
            .where(AuditLog.entity_id == entity_id)
            .where(AuditLog.tenant_id == tenant_id)
            .order_by(AuditLog.timestamp.desc())
            .limit(limit)
        )
        entries = [_serialize(a) for a in result.scalars().all()]
        return json.dumps({"activities": entries, "count": len(entries)}, default=str)
    except Exception as e:
        logger.exception("get_contact_history_handler failed")
        return json.dumps({"error": str(e)})


async def search_related_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Find semantically similar entities via unified_search."""
    try:
        db, tenant_id, _ = await _get_db_and_tenant(context)
        entity_type = arguments["entity_type"]
        entity_id = uuid.UUID(arguments["entity_id"])
        limit = arguments.get("limit", 5)

        from app.plugins.builtins.unified_search.search_engine import (
            find_similar_all_types,
        )

        similar = await find_similar_all_types(
            db, entity_type, entity_id, tenant_id, limit=limit
        )
        return json.dumps({"similar": similar}, default=str)
    except Exception as e:
        logger.exception("search_related_handler failed")
        return json.dumps({"error": str(e)})


async def summarize_mail_thread_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Summarize a mail thread using LLM."""
    try:
        import litellm

        db, tenant_id, _ = await _get_db_and_tenant(context)
        thread_id = arguments["thread_id"]
        limit = arguments.get("limit", 20)

        result = await db.execute(
            select(Mail)
            .where(Mail.thread_id == thread_id)
            .where(Mail.tenant_id == tenant_id)
            .order_by(Mail.received_at.asc())
            .limit(limit)
        )
        mails = result.scalars().all()
        if not mails:
            return json.dumps({"summary": "No mails found in thread", "count": 0})

        thread_text = "\n\n".join(
            f"From: {m.from_address}\nSubject: {m.subject}\nDate: {m.received_at}\nBody: {m.body_text[:500]}"
            for m in mails
        )

        response = await litellm.acompletion(
            model="gpt-4o-mini",
            messages=[
                {
                    "role": "system",
                    "content": "Fasse diesen E-Mail-Thread präzise zusammen. Antworte auf Deutsch.",
                },
                {"role": "user", "content": thread_text},
            ],
            temperature=0.3,
            max_tokens=300,
        )
        summary = response.choices[0].message.content or ""
        return json.dumps({"summary": summary, "count": len(mails)}, default=str)
    except Exception as e:
        logger.exception("summarize_mail_thread_handler failed")
        return json.dumps({"error": str(e)})


async def get_open_tasks_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Get open tasks (calendar entries) for a contact or company."""
    try:
        from datetime import UTC, datetime

        from app.plugins.builtins.calendar.models import (
            CalendarEntry,
            CalendarEntryLink,
        )

        db, tenant_id, _ = await _get_db_and_tenant(context)
        entity_type = arguments["entity_type"]
        entity_id = uuid.UUID(arguments["entity_id"])
        now = datetime.now(UTC)

        result = await db.execute(
            select(CalendarEntry)
            .join(CalendarEntryLink, CalendarEntryLink.entry_id == CalendarEntry.id)
            .where(CalendarEntryLink.entity_type == entity_type)
            .where(CalendarEntryLink.entity_id == entity_id)
            .where(CalendarEntry.tenant_id == tenant_id)
            .where(CalendarEntry.start_at > now)
            .where(CalendarEntry.status == "open")
            .order_by(CalendarEntry.start_at.asc())
            .limit(20)
        )
        tasks = [_serialize(e) for e in result.scalars().all()]
        return json.dumps({"tasks": tasks, "count": len(tasks)}, default=str)
    except Exception as e:
        logger.exception("get_open_tasks_handler failed")
        return json.dumps({"error": str(e)})


async def hybrid_search_handler(arguments: dict[str, Any], context: dict[str, Any]) -> str:
    """Perform hybrid search via unified_search search_engine."""
    try:
        from app.plugins.builtins.unified_search.search_engine import hybrid_search

        db, tenant_id, _ = await _get_db_and_tenant(context)
        query = arguments["query"]
        entity_types = arguments.get("entity_types")
        limit = arguments.get("limit", 20)

        query_analysis = {
            "normalized_query": query,
            "semantic_terms": [],
        }
        results = await hybrid_search(
            db, query_analysis, tenant_id, entity_types=entity_types, limit=limit
        )
        return json.dumps({"results": results, "count": len(results)}, default=str)
    except Exception as e:
        logger.exception("hybrid_search_handler failed")
        return json.dumps({"error": str(e)})


# ─── Registration ───


def register_context_tools(registry) -> None:
    """Register AI tools into the existing Tool Registry."""

    # Tool 1: get_contact_mails
    registry.register(
        name="get_contact_mails",
        description="Alle Mails eines Kontakts abrufen, sortiert nach Datum absteigend",
        parameters={
            "type": "object",
            "properties": {
                "contact_id": {"type": "string", "description": "UUID des Kontakts"},
                "limit": {"type": "integer", "default": 10, "description": "Max results"},
            },
            "required": ["contact_id"],
        },
        handler=get_contact_mails_handler,
        plugin_name="ai_proactive",
        required_permission="mail:read",
        category="context",
    )

    # Tool 2: get_contact_history
    registry.register(
        name="get_contact_history",
        description="Aktivitätsverlauf (Audit Log) für eine Entity abrufen",
        parameters={
            "type": "object",
            "properties": {
                "entity_id": {"type": "string", "description": "UUID der Entity"},
                "limit": {"type": "integer", "default": 20, "description": "Max results"},
            },
            "required": ["entity_id"],
        },
        handler=get_contact_history_handler,
        plugin_name="ai_proactive",
        required_permission="ai_proactive:read",
        category="context",
    )

    # Tool 3: search_related
    registry.register(
        name="search_related",
        description="Semantisch ähnliche Entities über unified_search finden",
        parameters={
            "type": "object",
            "properties": {
                "entity_type": {"type": "string", "description": "contact, mail, file, event"},
                "entity_id": {"type": "string", "description": "UUID der Entity"},
                "limit": {"type": "integer", "default": 5, "description": "Max results per type"},
            },
            "required": ["entity_type", "entity_id"],
        },
        handler=search_related_handler,
        plugin_name="ai_proactive",
        required_permission="search:read",
        category="context",
    )

    # Tool 4: summarize_mail_thread
    registry.register(
        name="summarize_mail_thread",
        description="E-Mail-Thread per LLM zusammenfassen",
        parameters={
            "type": "object",
            "properties": {
                "thread_id": {"type": "string", "description": "Thread ID"},
                "limit": {"type": "integer", "default": 20, "description": "Max mails to include"},
            },
            "required": ["thread_id"],
        },
        handler=summarize_mail_thread_handler,
        plugin_name="ai_proactive",
        required_permission="mail:read",
        category="context",
    )

    # Tool 5: get_open_tasks
    registry.register(
        name="get_open_tasks",
        description="Offene Aufgaben (Kalender-Termine) für einen Kontakt oder eine Firma abrufen",
        parameters={
            "type": "object",
            "properties": {
                "entity_type": {"type": "string", "description": "contact"},
                "entity_id": {"type": "string", "description": "UUID der Entity"},
            },
            "required": ["entity_type", "entity_id"],
        },
        handler=get_open_tasks_handler,
        plugin_name="ai_proactive",
        required_permission="ai_proactive:read",
        category="context",
    )

    # Tool 6: hybrid_search
    registry.register(
        name="hybrid_search",
        description="Hybride Volltext- und Semantiksuche über alle CRM-Entities via unified_search",
        parameters={
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Suchanfrage"},
                "entity_types": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Optional: filter by entity types",
                },
                "limit": {"type": "integer", "default": 20, "description": "Max results"},
            },
            "required": ["query"],
        },
        handler=hybrid_search_handler,
        plugin_name="ai_proactive",
        required_permission="search:read",
        category="context",
    )
