"""
Push-varsler til telefonens OS (Web Push/VAPID), FEATURE_BACKLOG.md
"Varsler: push til telefon". Bevisst helt frittstående fra
app/realtime.py (WebSocket-sanntid for åpne faner) -- push når appen ikke
er åpen i det hele tatt, helt andre leveringsmekanisme og bibliotek.

Valgfritt (PUSH_CONFIGURED, app/config.py) -- ingen nøkler satt betyr
push rett og slett ikke forsøkes, resten av varslingssystemet (in-app +
e-post) fungerer helt uendret. Samme grasiøs-degraderings-/feil-
isolasjons-mønster som app/email.py: en driftsfeil i selve utsendingen
lekker ALDRI til kalleren (create_notification skal alltid lykkes med å
skrive selve in-app-varselet, uansett hva som skjer her).
"""

from __future__ import annotations

import asyncio
import json
import traceback

from pywebpush import WebPushException, webpush

from .config import settings


def _send_sync(subscription_info: dict, payload: dict) -> None:
    webpush(
        subscription_info=subscription_info,
        data=json.dumps(payload),
        vapid_private_key=settings.VAPID_PRIVATE_KEY,
        vapid_claims={"sub": settings.VAPID_SUBJECT},
    )


async def send_push_to_user(conn, user_id: str, title: str, body: str, link_path: str) -> None:
    """Sender til ALLE enheter brukeren har abonnert (flere nettlesere/
    telefoner er normalt). Et utløpt/tilbakekalt abonnement (404/410 fra
    push-tjenesten) ryddes bort her -- ikke behandlet som en feil, bare
    forventet livssyklus for et push-abonnement."""
    if not settings.PUSH_CONFIGURED:
        return
    rows = await conn.fetch(
        "SELECT id::text AS id, endpoint, p256dh, auth FROM push_subscription WHERE user_id = $1",
        user_id,
    )
    if not rows:
        return
    payload = {"title": title, "body": body, "link_path": link_path}
    for row in rows:
        subscription_info = {
            "endpoint": row["endpoint"],
            "keys": {"p256dh": row["p256dh"], "auth": row["auth"]},
        }
        try:
            await asyncio.to_thread(_send_sync, subscription_info, payload)
        except WebPushException as exc:
            status = exc.response.status_code if exc.response is not None else None
            if status in (404, 410):
                await conn.execute("DELETE FROM push_subscription WHERE id = $1", row["id"])
            else:
                traceback.print_exc()
        except Exception:
            traceback.print_exc()
