import type { GustitoClient } from './supabase';

// Llave publica VAPID (identidad de envio). Es publica, puede ir en el cliente.
// La privada vive SOLO en la Edge Function (secreto), nunca aqui.
export const VAPID_PUBLIC =
  'BEqfjYl3Q2GEcku9gc_zTOCAZewySE4L9q_C6_2S0aDUA68iY0Zq-cNtTNLFM1viTf2Uc2heCNObGeO75d3Ezgk';

function base64UrlAUint8(base64: string): Uint8Array {
  const pad = '='.repeat((4 - (base64.length % 4)) % 4);
  const b64 = (base64 + pad).replace(/-/g, '+').replace(/_/g, '/');
  const raw = atob(b64);
  const out = new Uint8Array(raw.length);
  for (let i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
  return out;
}

export function pushSoportado(): boolean {
  return (
    typeof window !== 'undefined' &&
    'Notification' in window &&
    'serviceWorker' in navigator &&
    'PushManager' in window
  );
}

/**
 * Suscribe el teléfono a notificaciones push y guarda la suscripción en la BD.
 * Requiere que el permiso ya esté concedido (Notification.permission === 'granted').
 * Devuelve true si quedó suscrito.
 */
export async function suscribirPush(supabase: GustitoClient, contexto: string): Promise<boolean> {
  if (!pushSoportado()) return false;
  if (Notification.permission !== 'granted') return false;
  try {
    const reg = await navigator.serviceWorker.ready;
    let sub = await reg.pushManager.getSubscription();
    if (!sub) {
      sub = await reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: base64UrlAUint8(VAPID_PUBLIC) as unknown as BufferSource,
      });
    }
    const json = sub.toJSON();
    if (!json.endpoint || !json.keys?.p256dh || !json.keys?.auth) return false;
    const { error } = await supabase.rpc('guardar_push_sub', {
      p_endpoint: json.endpoint,
      p_p256dh: json.keys.p256dh,
      p_auth: json.keys.auth,
      p_contexto: contexto,
    });
    return !error;
  } catch {
    return false;
  }
}

/**
 * Para el CLIENTE (sin cuenta): pide permiso, suscribe el aparato y guarda la
 * suscripción ligada a SU pedido (no a un perfil). Así recibe los avisos del
 * estado de su pedido (en preparación, va en camino, listo). Best-effort: si el
 * cliente no da permiso o el navegador no soporta push, no pasa nada.
 */
export async function activarPushPedido(supabase: GustitoClient, pedidoId: string): Promise<boolean> {
  if (!pushSoportado()) return false;
  try {
    if (Notification.permission === 'default') {
      const permiso = await Notification.requestPermission();
      if (permiso !== 'granted') return false;
    }
    if (Notification.permission !== 'granted') return false;
    const reg = await navigator.serviceWorker.ready;
    let sub = await reg.pushManager.getSubscription();
    if (!sub) {
      sub = await reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: base64UrlAUint8(VAPID_PUBLIC) as unknown as BufferSource,
      });
    }
    const json = sub.toJSON();
    if (!json.endpoint || !json.keys?.p256dh || !json.keys?.auth) return false;
    const { error } = await supabase.rpc('guardar_push_pedido', {
      p_pedido_id: pedidoId,
      p_endpoint: json.endpoint,
      p_p256dh: json.keys.p256dh,
      p_auth: json.keys.auth,
    });
    return !error;
  } catch {
    return false;
  }
}

/** Pide permiso (requiere gesto del usuario) y suscribe. Devuelve el estado final. */
export async function activarPush(
  supabase: GustitoClient,
  contexto: string,
): Promise<NotificationPermission | 'unsupported'> {
  if (!pushSoportado()) return 'unsupported';
  const permiso = await Notification.requestPermission();
  if (permiso === 'granted') await suscribirPush(supabase, contexto);
  return permiso;
}
