"""Web push notifications — a real OS-level notification (Android home
screen / lock screen / status bar, or desktop notification) for a new order
message or an order status change, even when the site isn't open. Uses the
browser's own push service via VAPID (no third-party push account needed).

Entirely opt-in and fail-safe: if VAPID isn't configured, or a subscription
has gone stale, or the push service errors, this silently no-ops rather than
ever raising up into the calling code path (a message or status update must
never fail because a push notification couldn't be delivered)."""

import json
import logging

from django.conf import settings
from pywebpush import WebPushException, webpush

from accounts.supabase_client import get_client

logger = logging.getLogger(__name__)


def save_subscription(user_id, subscription):
    """subscription is the raw dict from the browser's PushSubscription.toJSON()."""
    endpoint = subscription.get('endpoint')
    keys = subscription.get('keys') or {}
    if not endpoint or not keys.get('p256dh') or not keys.get('auth'):
        return False
    get_client().table('pickker_push_subscriptions').upsert({
        'user_id': user_id,
        'endpoint': endpoint,
        'p256dh': keys['p256dh'],
        'auth': keys['auth'],
    }, on_conflict='endpoint').execute()
    return True


def remove_subscription(endpoint):
    get_client().table('pickker_push_subscriptions').delete().eq('endpoint', endpoint).execute()


def send_push_to_user(user_id, title, body, url='/'):
    """Best-effort — never raises. Sends to every device/browser the user
    has subscribed on, and cleans up any subscription the push service
    reports as gone (expired or the user revoked permission)."""
    if not settings.VAPID_PRIVATE_KEY:
        return

    client = get_client()
    subs = client.table('pickker_push_subscriptions').select('*').eq('user_id', user_id).execute().data
    if not subs:
        return

    payload = json.dumps({'title': title, 'body': body, 'url': url})
    for sub in subs:
        subscription_info = {
            'endpoint': sub['endpoint'],
            'keys': {'p256dh': sub['p256dh'], 'auth': sub['auth']},
        }
        try:
            webpush(
                subscription_info=subscription_info,
                data=payload,
                vapid_private_key=settings.VAPID_PRIVATE_KEY,
                vapid_claims={'sub': f'mailto:{settings.VAPID_CLAIMS_EMAIL}'},
            )
        except WebPushException as exc:
            status_code = getattr(exc.response, 'status_code', None)
            if status_code in (404, 410):
                # Subscription is gone (expired, or the user revoked
                # permission) — stop trying it on every future notification.
                remove_subscription(sub['endpoint'])
            else:
                logger.warning('Push send failed for user %s: %s', user_id, exc)
        except Exception:
            logger.exception('Unexpected push error for user %s', user_id)


def push_new_message(order, sender_role, message_text):
    """Push-notifies the OTHER party in an order's chat — same
    recipient-resolution convention as order_emails.notify_new_message."""
    if sender_role == 'customer':
        recipient_id = order.get('picker_id')
    else:
        recipient_id = order.get('customer_id')
    if not recipient_id:
        return
    body = message_text if len(message_text) <= 100 else message_text[:97] + '...'
    url = f"/orders/{order['id']}/" if sender_role == 'picker' else f"/accounts/picker/orders/{order['id']}/"
    send_push_to_user(recipient_id, f"New message — Order #{order['id']}", body, url)


def push_order_status_changed(order, status_label):
    """Push-notifies the customer when their order's status changes."""
    customer_id = order.get('customer_id')
    if not customer_id:
        return
    send_push_to_user(
        customer_id,
        f"Order #{order['id']} update",
        f'Your order is now: {status_label}',
        f"/orders/{order['id']}/",
    )


def push_payment_released(order):
    """Push-notifies the picker/company (order.picker_id) once admin
    releases the held payment for this order — see
    accounts/views.py::admin_release_payment."""
    picker_id = order.get('picker_id')
    if not picker_id:
        return
    send_push_to_user(
        picker_id,
        f"Payment released — Order #{order['id']}",
        'The held payment for this order has been released to you.',
        f"/accounts/picker/orders/{order['id']}/",
    )
