from typing import Any, cast

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import asc, desc, func, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from app.auth.tenant import get_current_restaurant, get_tenant_session
from app.models.notification import Notification, NotificationRead, UnreadCountResponse
from app.models.restaurant import Restaurant

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


@router.get("/", response_model=list[NotificationRead])
async def list_notifications(
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    restaurant: Restaurant = Depends(get_current_restaurant),
    session: AsyncSession = Depends(get_tenant_session),
) -> Any:
    restaurant_id_col = cast(Any, Notification.restaurant_id)
    is_read_col = cast(Any, Notification.is_read)
    created_at_col = cast(Any, Notification.created_at)
    stmt = (
        select(Notification)
        .where(restaurant_id_col == restaurant.id)
        .order_by(asc(is_read_col), desc(created_at_col))
        .limit(limit)
        .offset(offset)
    )
    result = await session.execute(stmt)
    return list(result.scalars().all())


@router.get("/unread-count", response_model=UnreadCountResponse)
async def unread_count(
    restaurant: Restaurant = Depends(get_current_restaurant),
    session: AsyncSession = Depends(get_tenant_session),
) -> UnreadCountResponse:
    restaurant_id_col = cast(Any, Notification.restaurant_id)
    is_read_col = cast(Any, Notification.is_read)
    result = await session.execute(
        select(func.count()).where(
            restaurant_id_col == restaurant.id,
            is_read_col.is_(False),
        )
    )
    return UnreadCountResponse(count=int(result.scalar() or 0))


@router.post("/{notification_id}/read", response_model=NotificationRead)
async def mark_notification_as_read(
    notification_id: str,
    restaurant: Restaurant = Depends(get_current_restaurant),
    session: AsyncSession = Depends(get_tenant_session),
) -> NotificationRead:
    result = await session.execute(
        select(Notification).where(
            Notification.id == notification_id,
            Notification.restaurant_id == restaurant.id,
        )
    )
    notification = result.scalar_one_or_none()
    if notification is None:
        raise HTTPException(status_code=404, detail="Notification not found")

    notification.is_read = True
    session.add(notification)
    await session.commit()
    await session.refresh(notification)
    return NotificationRead.model_validate(notification)


@router.post("/read-all")
async def mark_all_notifications_as_read(
    restaurant: Restaurant = Depends(get_current_restaurant),
    session: AsyncSession = Depends(get_tenant_session),
) -> dict[str, int]:
    restaurant_id_col = cast(Any, Notification.restaurant_id)
    is_read_col = cast(Any, Notification.is_read)
    unread_count_result = await session.execute(
        select(func.count()).where(
            restaurant_id_col == restaurant.id,
            is_read_col.is_(False),
        )
    )
    unread_count = int(unread_count_result.scalar() or 0)

    result = await session.execute(
        update(Notification)
        .where(
            restaurant_id_col == restaurant.id,
            is_read_col.is_(False),
        )
        .values(is_read=True)
    )
    _ = result
    await session.commit()
    return {"updated": unread_count}
