"""API системных уведомлений (ТЗ 3.21).

Подписка — свойство устройства, а не пользователя: один человек приходит и с
телефона, и с ноутбука, и каждому нужен свой адрес доставки. Поэтому подписок
может быть много, а `endpoint` уникален глобально (в браузерном профиле она одна)
— при входе другим аккаунтом подписка перепривязывается, а не размножается.

`publish` здесь не нужен: подписка не меняет то, что видит открытая вкладка.
"""

from fastapi import APIRouter, HTTPException, Request
from sqlalchemy import select

from app.config import get_settings
from app.dependencies import DbDep, UserIdDep
from app.models import PushSubscription
from app.schemas import (
    PushConfigOut,
    PushSubscribeIn,
    PushSubscriptionOut,
    PushUnsubscribeIn,
)
from app.services.push import delete_subscription, save_subscription

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


def _out(sub: PushSubscription) -> PushSubscriptionOut:
    return PushSubscriptionOut.model_validate(sub)


@router.get("/config", response_model=PushConfigOut)
async def get_config(_user_id: UserIdDep) -> PushConfigOut:
    """Состояние push на сервере: без ключей VAPID подписываться некуда, и фронт
    показывает блок настроек выключенным, а не падает на подписке."""
    settings = get_settings()
    return PushConfigOut(
        enabled=settings.push_enabled,
        public_key=settings.vapid_public_key or None,
    )


@router.post("/subscribe", response_model=PushSubscriptionOut)
async def subscribe(
    schema: PushSubscribeIn, request: Request, db: DbDep, user_id: UserIdDep
) -> PushSubscriptionOut:
    """Сохранить (или перепривязать) подписку устройства."""
    if not get_settings().push_enabled:
        raise HTTPException(status_code=503, detail="Push is not configured")
    sub = save_subscription(
        db,
        user_id,
        schema.endpoint,
        schema.keys.p256dh,
        schema.keys.auth,
        request.headers.get("user-agent"),
    )
    db.commit()
    return _out(sub)


@router.delete("/subscribe")
async def unsubscribe(
    schema: PushUnsubscribeIn, db: DbDep, user_id: UserIdDep
) -> dict[str, bool]:
    """Отписаться идемпотентно: браузер мог уже потерять подписку сам."""
    delete_subscription(db, user_id, schema.endpoint)
    db.commit()
    # {ok: true}, а не 204: у фронта один разбор ответа (res.json()), и пустое
    # тело ломало бы его — так же отвечает удаление MCP-токена
    return {"ok": True}


@router.get("/subscriptions", response_model=list[PushSubscriptionOut])
async def list_subscriptions(db: DbDep, user_id: UserIdDep) -> list[PushSubscriptionOut]:
    """Устройства пользователя — для строки «подключено устройств: N» в настройках."""
    rows = db.scalars(
        select(PushSubscription)
        .where(PushSubscription.user_id == user_id)
        .order_by(PushSubscription.created_at)
    ).all()
    return [_out(row) for row in rows]


@router.delete("/subscriptions/{sub_id}")
async def delete_device(sub_id: int, db: DbDep, user_id: UserIdDep) -> dict[str, bool]:
    """Убрать конкретное устройство. Чужую подписку не отдаём и не удаляем —
    отвечаем 404, чтобы по коду нельзя было даже узнать о её существовании."""
    sub = db.get(PushSubscription, sub_id)
    if sub is None or sub.user_id != user_id:
        raise HTTPException(status_code=404, detail="Subscription not found")
    db.delete(sub)
    db.commit()
    return {"ok": True}
