"""Notification routes."""

from __future__ import annotations

import uuid

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import and_, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.db import get_db
from app.core.notifications import (
    get_unread_count,
    list_notifications,
    mark_notification_read,
)
from app.deps import require_permission
from app.models.notification import (
    NotificationPreference,
    NotificationType,
)
from app.schemas.common import NotificationPreferenceUpdate, UnreadCountResponse

router = APIRouter(prefix="/api/v1/notifications", tags=["notifications"])


@router.get("")
async def list_notifications_endpoint(
    page: int = Query(1, ge=1),
    page_size: int = Query(25, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:read")),
):
    """List notifications (unread first)."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    return await list_notifications(db, tenant_id, user_id, page, page_size)


@router.patch("/{notification_id}/read")
async def mark_notification_read_endpoint(
    notification_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:write")),
):
    """Mark a notification as read."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    try:
        nid = uuid.UUID(notification_id)
    except ValueError:
        raise HTTPException(
            400, detail={"detail": "Invalid notification_id", "code": "invalid_id"}
        ) from None

    notif = await mark_notification_read(db, tenant_id, user_id, nid)
    if notif is None:
        raise HTTPException(404, detail={"detail": "Notification not found", "code": "not_found"})

    return {
        "id": str(notif.id),
        "type": notif.type,
        "title": notif.title,
        "body": notif.body,
        "read_at": notif.read_at.isoformat() if notif.read_at else None,
        "created_at": notif.created_at.isoformat() if notif.created_at else None,
    }


@router.get("/unread-count")
async def unread_count_endpoint(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:read")),
):
    """Get unread notification count."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    count = await get_unread_count(db, tenant_id, user_id)
    return {"count": count}


@router.get("/types")
async def list_notification_types(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:read")),
):
    """List all registered notification types with the user's preference."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    # Fetch all registered types
    types_result = await db.execute(select(NotificationType).order_by(NotificationType.plugin_name, NotificationType.category))
    types = types_result.scalars().all()

    # Fetch user's preferences
    prefs_result = await db.execute(
        select(NotificationPreference).where(
            and_(
                NotificationPreference.user_id == user_id,
                NotificationPreference.tenant_id == tenant_id,
            )
        )
    )
    prefs = {p.type_key: p.is_enabled for p in prefs_result.scalars().all()}

    items = []
    for t in types:
        if t.type_key in prefs:
            is_enabled = prefs[t.type_key]
        else:
            is_enabled = t.is_enabled_by_default
        items.append({
            "type_key": t.type_key,
            "plugin_name": t.plugin_name,
            "category": t.category,
            "label": t.label,
            "description": t.description,
            "is_enabled_by_default": t.is_enabled_by_default,
            "is_enabled": is_enabled,
        })

    return {"items": items}


@router.get("/preferences")
async def list_preferences(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:read")),
):
    """List user's notification preferences."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    result = await db.execute(
        select(NotificationPreference).where(
            and_(
                NotificationPreference.user_id == user_id,
                NotificationPreference.tenant_id == tenant_id,
            )
        )
    )
    prefs = result.scalars().all()

    return {
        "items": [
            {"type_key": p.type_key, "is_enabled": p.is_enabled}
            for p in prefs
        ]
    }


@router.patch("/preferences/{type_key}")
async def update_preference(
    type_key: str,
    data: NotificationPreferenceUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("notifications:write")),
):
    """Update user's preference for a notification type (upsert)."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])

    # Check that the type exists
    type_result = await db.execute(
        select(NotificationType).where(NotificationType.type_key == type_key)
    )
    type_row = type_result.scalar_one_or_none()
    if type_row is None:
        raise HTTPException(
            404,
            detail={"detail": f"Notification type '{type_key}' not found", "code": "not_found"},
        )

    # Upsert preference
    result = await db.execute(
        select(NotificationPreference).where(
            and_(
                NotificationPreference.user_id == user_id,
                NotificationPreference.type_key == type_key,
                NotificationPreference.tenant_id == tenant_id,
            )
        )
    )
    pref = result.scalar_one_or_none()

    if pref is None:
        pref = NotificationPreference(
            tenant_id=tenant_id,
            user_id=user_id,
            type_key=type_key,
            is_enabled=data.is_enabled,
        )
        db.add(pref)
    else:
        pref.is_enabled = data.is_enabled

    await db.flush()

    return {"type_key": type_key, "is_enabled": pref.is_enabled}
