"""API routes for the AI Proactive plugin.

Endpoints: context tracking, suggestions CRUD, SSE stream, settings, stats.
"""

from __future__ import annotations

import asyncio
import json
import logging
import uuid
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.db import get_db, set_tenant_context
from app.core.event_bus import get_event_bus
from app.deps import get_current_user, require_permission
from app.plugins.builtins.ai_proactive.models import (
    ContextLog,
    ProactiveSettings,
    ProactiveSuggestion,
)
from app.plugins.builtins.ai_proactive.schemas import (
    ActRequest,
    ActResponse,
    ContextReport,
    SettingsResponse,
    SettingsUpdate,
    SuggestionListResponse,
    SuggestionResponse,
    StatsResponse,
)
from app.plugins.builtins.ai_proactive.services import (
    execute_suggested_action,
    get_active_suggestions,
    get_sse_queue,
    get_stats,
    get_user_settings,
    mark_dismissed,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/ai-proactive", tags=["ai-proactive"])


def _suggestion_to_response(s: ProactiveSuggestion) -> SuggestionResponse:
    """Convert a ProactiveSuggestion model to SuggestionResponse."""
    return SuggestionResponse(
        id=str(s.id),
        entity_type=s.entity_type,
        entity_id=str(s.entity_id) if s.entity_id else None,
        suggestion_type=s.suggestion_type,
        title=s.title,
        content=s.content,
        confidence=s.confidence,
        actions=s.actions or [],
        created_at=s.created_at,
        is_dismissed=s.is_dismissed,
        is_acted_upon=s.is_acted_upon,
    )


def _settings_to_response(s: ProactiveSettings) -> SettingsResponse:
    """Convert ProactiveSettings model to SettingsResponse."""
    return SettingsResponse(
        enabled=s.enabled,
        suggestion_categories=s.suggestion_categories or [],
        confidence_threshold=s.confidence_threshold,
        rate_limit_seconds=s.rate_limit_seconds,
        model=s.model,
        heartbeat_enabled=s.heartbeat_enabled,
        heartbeat_interval_seconds=s.heartbeat_interval_seconds,
        heartbeat_target_room=s.heartbeat_target_room,
    )


# ─── Context Tracking ───


@router.post("/context", dependencies=[Depends(require_permission("ai_proactive:read"))])
async def report_context(
    context: ContextReport,
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Frontend reports current context (page, entity).

    Stores context log entry and publishes event for proactive engine.
    """
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    # Parse entity_id if present
    entity_id: uuid.UUID | None = None
    if context.entity_id:
        try:
            entity_id = uuid.UUID(context.entity_id)
        except (ValueError, TypeError):
            entity_id = None

    # Store context log
    log_entry = ContextLog(
        tenant_id=tenant_id,
        user_id=user_id,
        page=context.page,
        entity_type=context.entity_type,
        entity_id=entity_id,
        entity_data=context.entity_data or {},
    )
    db.add(log_entry)
    await db.flush()

    # Publish event
    event_bus = get_event_bus()
    event_name = (
        "context.entity_selected"
        if context.entity_type and context.entity_id
        else "context.view_changed"
    )
    payload = {
        "user_id": str(user_id),
        "tenant_id": str(tenant_id),
        "page": context.page,
        "entity_type": context.entity_type,
        "entity_id": str(entity_id) if entity_id else None,
        "entity_data": context.entity_data or {},
    }
    await event_bus.publish(event_name, payload)

    return {"status": "ok"}


# ─── Suggestions ───


@router.get(
    "/suggestions",
    dependencies=[Depends(require_permission("ai_proactive:read"))],
    response_model=SuggestionListResponse,
)
async def get_suggestions(
    entity_type: str | None = Query(None),
    entity_id: str | None = Query(None),
    limit: int = Query(10, ge=1, le=100),
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get active suggestions for the current user."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    eid: uuid.UUID | None = None
    if entity_id:
        try:
            eid = uuid.UUID(entity_id)
        except (ValueError, TypeError):
            eid = None

    suggestions = await get_active_suggestions(
        db, tenant_id, user_id, entity_type=entity_type, entity_id=eid, limit=limit
    )
    items = [_suggestion_to_response(s) for s in suggestions]
    return SuggestionListResponse(items=items, total=len(items))


@router.post(
    "/suggestions/{suggestion_id}/dismiss",
    dependencies=[Depends(require_permission("ai_proactive:write"))],
)
async def dismiss_suggestion(
    suggestion_id: str,
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Mark a suggestion as dismissed."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    try:
        sid = uuid.UUID(suggestion_id)
    except (ValueError, TypeError):
        raise HTTPException(status_code=400, detail="Invalid suggestion ID")

    success = await mark_dismissed(db, sid, user_id, tenant_id)
    if not success:
        raise HTTPException(status_code=404, detail="Suggestion not found")
    return {"status": "ok"}


@router.post(
    "/suggestions/{suggestion_id}/act",
    dependencies=[Depends(require_permission("ai_proactive:write"))],
    response_model=ActResponse,
)
async def act_on_suggestion(
    suggestion_id: str,
    action: ActRequest,
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Execute a suggested action."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    try:
        sid = uuid.UUID(suggestion_id)
    except (ValueError, TypeError):
        raise HTTPException(status_code=400, detail="Invalid suggestion ID")

    result = await execute_suggested_action(
        db, sid, action.action_index, user_id, tenant_id, current_user
    )
    return ActResponse(
        success=result.get("success", False),
        data=result.get("data"),
        error=result.get("error"),
    )


# ─── SSE Stream ───


@router.get(
    "/suggestions/stream",
    dependencies=[Depends(require_permission("ai_proactive:read"))],
)
async def stream_suggestions(
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """SSE stream: push new suggestions in real-time.

    Uses an asyncio.Queue per user. Heartbeat every 30s.
    """
    user_id = str(current_user["user_id"])

    async def event_generator():
        queue = get_sse_queue(user_id)
        while True:
            try:
                suggestion = await asyncio.wait_for(queue.get(), timeout=30)
                yield f"data: {json.dumps(suggestion, default=str)}\n\n"
            except asyncio.TimeoutError:
                yield ": keepalive\n\n"

    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no",
        },
    )


# ─── Settings ───


@router.get(
    "/settings",
    dependencies=[Depends(require_permission("ai_proactive:read"))],
    response_model=SettingsResponse,
)
async def get_settings(
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get proactive AI settings for the current user."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    settings = await get_user_settings(db, tenant_id, user_id)
    return _settings_to_response(settings)


@router.put(
    "/settings",
    dependencies=[Depends(require_permission("ai_proactive:config"))],
    response_model=SettingsResponse,
)
async def update_settings(
    settings_update: SettingsUpdate,
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Update proactive AI settings for the current user."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    settings = await get_user_settings(db, tenant_id, user_id)

    update_data = settings_update.model_dump(exclude_unset=True)
    for field, val in update_data.items():
        setattr(settings, field, val)

    await db.flush()
    return _settings_to_response(settings)


# ─── Stats ───


@router.get(
    "/stats",
    dependencies=[Depends(require_permission("ai_proactive:read"))],
    response_model=StatsResponse,
)
async def get_stats_endpoint(
    current_user: dict[str, Any] = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get proactive AI usage statistics for the current user."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    stats = await get_stats(db, tenant_id, user_id)
    return StatsResponse(**stats)
