// Edge Function: enviar-push
// Recibe { pedido_id, evento } (lo llama un trigger de la BD via pg_net) y envia
// notificaciones Web Push a los destinatarios segun el evento:
//   - nuevo_pedido -> el dueno del restaurante
//   - asignado     -> el repartidor asignado a ese pedido
//   - listo_pool   -> los repartidores disponibles del restaurante (si esta sin asignar)
// Valida un secreto compartido (x-push-secret). Envio cifrado con la libreria web-push.
import webpush from 'npm:web-push@3.6.7';

const CORS = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type, x-push-secret',
  'Access-Control-Allow-Methods': 'POST, OPTIONS',
};
const json = (obj: unknown, status = 200) =>
  new Response(JSON.stringify(obj), { status, headers: { ...CORS, 'Content-Type': 'application/json' } });

const SUPABASE_URL = Deno.env.get('SUPABASE_URL')!;
const SERVICE = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
const VAPID_PUBLIC = Deno.env.get('VAPID_PUBLIC')!;
const VAPID_PRIVATE = Deno.env.get('VAPID_PRIVATE')!;
const VAPID_SUBJECT = Deno.env.get('VAPID_SUBJECT') ?? 'mailto:soporte@gustitoxpress.app';
const PUSH_SECRET = Deno.env.get('PUSH_SECRET')!;

webpush.setVapidDetails(VAPID_SUBJECT, VAPID_PUBLIC, VAPID_PRIVATE);

const svc = { apikey: SERVICE, Authorization: `Bearer ${SERVICE}` };
const rest = (path: string) => fetch(`${SUPABASE_URL}/rest/v1/${path}`, { headers: svc }).then((r) => r.json());

function mensaje(evento: string, ped: Record<string, unknown>) {
  const codigo = String(ped.codigo ?? 'Pedido');
  const total = Number(ped.total_usd ?? 0).toFixed(2);
  // Avisos a NEGOCIO / REPARTIDOR
  if (evento === 'nuevo_pedido') {
    const tipo = ped.tipo_entrega === 'mesa' ? `Mesa ${ped.mesa ?? ''}`.trim() : ped.tipo_entrega === 'delivery' ? 'Delivery' : 'Para llevar';
    return { titulo: '🔔 Nuevo pedido', cuerpo: `Pedido ${codigo} · ${tipo} · $${total}. Ábrelo para prepararlo.`, url: '/', tag: `pedido-${ped.id}` };
  }
  if (evento === 'asignado') {
    return { titulo: '🛵 Nueva entrega', cuerpo: `Pedido ${codigo} para ${ped.cliente_nombre ?? 'un cliente'}. Ábrelo para ver los detalles.`, url: '/', tag: `entrega-${ped.id}` };
  }
  if (evento === 'listo_pool') {
    return { titulo: '🛵 Entrega disponible', cuerpo: `Pedido ${codigo} listo para recoger. Tómalo antes de que otro lo haga.`, url: '/', tag: `pool-${ped.id}` };
  }
  // Avisos al CLIENTE (personalizados con su primer nombre)
  const primerNombre = String(ped.cliente_nombre ?? '').trim().split(/\s+/)[0] ?? '';
  const tuPedido = primerNombre ? `${primerNombre}, tu pedido ${codigo}` : `Tu pedido ${codigo}`;
  const urlCliente = `/pedido/${ped.id}`;
  if (evento === 'cliente_preparando') {
    const min = Number(ped.tiempo_estimado_min ?? 0);
    const tiempo = min > 0 ? ` Estará listo en unos ${min} min.` : '';
    return { titulo: '👨‍🍳 Manos a la obra', cuerpo: `${tuPedido} ya está en preparación.${tiempo}`, url: urlCliente, tag: `estado-${ped.id}` };
  }
  if (evento === 'cliente_en_camino') {
    return { titulo: '🛵 Tu pedido va en camino', cuerpo: `${tuPedido} ya salió hacia tu dirección. Síguelo en vivo en el mapa.`, url: urlCliente, tag: `estado-${ped.id}` };
  }
  if (evento === 'cliente_listo') {
    const cuerpo = ped.tipo_entrega === 'mesa'
      ? `${tuPedido} está listo y va para tu mesa.`
      : `${tuPedido} está listo para recoger.`;
    return { titulo: '✅ ¡Tu pedido está listo!', cuerpo, url: urlCliente, tag: `estado-${ped.id}` };
  }
  return { titulo: 'Gustito Xpress', cuerpo: `Pedido ${codigo}`, url: urlCliente, tag: `estado-${ped.id}` };
}

async function perfilesDestino(evento: string, ped: Record<string, unknown>): Promise<string[]> {
  if (evento === 'nuevo_pedido') {
    const filas = await rest(`perfiles?restaurante_id=eq.${ped.restaurante_id}&rol=eq.dueno&select=id`);
    return (filas as { id: string }[]).map((f) => f.id);
  }
  if (evento === 'asignado') {
    if (!ped.repartidor_id) return [];
    const filas = await rest(`repartidores?id=eq.${ped.repartidor_id}&select=perfil_id`);
    return (filas as { perfil_id: string }[]).map((f) => f.perfil_id);
  }
  // listo_pool
  if (ped.repartidor_id) return [];
  const filas = await rest(`repartidores?restaurante_id=eq.${ped.restaurante_id}&estado=eq.disponible&select=perfil_id`);
  return (filas as { perfil_id: string }[]).map((f) => f.perfil_id);
}

// Envia un payload a una lista de suscripciones y limpia las muertas.
async function despachar(subs: { endpoint: string; p256dh: string; auth: string }[], payload: string) {
  let enviados = 0;
  const muertas: string[] = [];
  await Promise.all(
    subs.map(async (s) => {
      try {
        await webpush.sendNotification({ endpoint: s.endpoint, keys: { p256dh: s.p256dh, auth: s.auth } }, payload);
        enviados++;
      } catch (e) {
        const code = (e as { statusCode?: number }).statusCode;
        if (code === 404 || code === 410) muertas.push(s.endpoint);
      }
    }),
  );
  for (const ep of muertas) {
    await fetch(`${SUPABASE_URL}/rest/v1/push_subs?endpoint=eq.${encodeURIComponent(ep)}`, { method: 'DELETE', headers: svc });
  }
  return { enviados, muertas: muertas.length };
}

// Aviso al MESERO asignado (o al dueño si la mesa no tiene mesero): el cliente
// llamo al mesero o pidio la cuenta. No hay pedido de por medio, es la cuenta.
async function avisarLlamada(cuentaId: string, tipo: string) {
  const ctas = await rest(`cuentas_mesa?id=eq.${cuentaId}&select=mesa,mesero_id,restaurante_id`);
  const cta = (ctas as Record<string, unknown>[])[0];
  if (!cta) return json({ ok: true, enviados: 0, motivo: 'cuenta no existe' });
  let perfiles: string[] = cta.mesero_id ? [String(cta.mesero_id)] : [];
  if (perfiles.length === 0) {
    // Mesa sin mesero asignado: avisar a TODOS los meseros y al dueño.
    const filas = await rest(`perfiles?restaurante_id=eq.${cta.restaurante_id}&rol=in.(staff,dueno)&select=id`);
    perfiles = (filas as { id: string }[]).map((d) => d.id);
  }
  if (perfiles.length === 0) return json({ ok: true, enviados: 0, motivo: 'sin destinatarios' });
  const inList = `(${perfiles.map((p) => `"${p}"`).join(',')})`;
  const subs = (await rest(`push_subs?perfil_id=in.${inList}&select=endpoint,p256dh,auth`)) as {
    endpoint: string; p256dh: string; auth: string;
  }[];
  if (!subs || subs.length === 0) return json({ ok: true, enviados: 0, motivo: 'sin suscripciones' });
  const mesa = String(cta.mesa ?? '');
  const msg =
    tipo === 'cuenta'
      ? { titulo: '💵 Piden la cuenta', cuerpo: `Mesa ${mesa}: el cliente pide la cuenta.`, url: '/', tag: `llamada-${cuentaId}` }
      : { titulo: '🔔 Te llaman de una mesa', cuerpo: `Mesa ${mesa} te esta llamando. Ve para alla.`, url: '/', tag: `llamada-${cuentaId}` };
  const r = await despachar(subs, JSON.stringify(msg));
  return json({ ok: true, ...r });
}

Deno.serve(async (req) => {
  if (req.method === 'OPTIONS') return new Response('ok', { headers: CORS });
  if (req.method !== 'POST') return json({ error: 'Metodo no permitido' }, 405);
  if (req.headers.get('x-push-secret') !== PUSH_SECRET) return json({ error: 'No autorizado' }, 401);

  try {
    const body = await req.json();
    const { evento } = body;
    if (!evento) return json({ error: 'Falta evento' }, 400);

    // Aviso de mesa (llamar al mesero / pedir la cuenta): no lleva pedido_id.
    if (evento === 'mesero_llamada') {
      if (!body.cuenta_id) return json({ error: 'Falta cuenta_id' }, 400);
      return await avisarLlamada(String(body.cuenta_id), String(body.tipo ?? 'mesero'));
    }

    const pedido_id = body.pedido_id;
    if (!pedido_id) return json({ error: 'Faltan pedido_id / evento' }, 400);

    const peds = await rest(
      `pedidos?id=eq.${pedido_id}&select=id,codigo,restaurante_id,repartidor_id,estado,tipo_entrega,cliente_nombre,total_usd,mesa,tiempo_estimado_min,push_endpoint,push_p256dh,push_auth`,
    );
    const ped = (peds as Record<string, unknown>[])[0];
    if (!ped) return json({ error: 'Pedido no existe' }, 404);

    let subs: { endpoint: string; p256dh: string; auth: string }[];
    if (evento.startsWith('cliente_')) {
      // El destinatario es el propio cliente: su suscripcion vive en el pedido.
      if (!ped.push_endpoint || !ped.push_p256dh || !ped.push_auth) {
        return json({ ok: true, enviados: 0, motivo: 'cliente sin suscripcion' });
      }
      subs = [{ endpoint: String(ped.push_endpoint), p256dh: String(ped.push_p256dh), auth: String(ped.push_auth) }];
    } else {
      const perfiles = await perfilesDestino(evento, ped);
      if (perfiles.length === 0) return json({ ok: true, enviados: 0, motivo: 'sin destinatarios' });
      const inList = `(${perfiles.map((p) => `"${p}"`).join(',')})`;
      subs = (await rest(`push_subs?perfil_id=in.${inList}&select=endpoint,p256dh,auth`)) as {
        endpoint: string;
        p256dh: string;
        auth: string;
      }[];
    }
    if (!subs || subs.length === 0) return json({ ok: true, enviados: 0, motivo: 'sin suscripciones' });

    const payload = JSON.stringify(mensaje(evento, ped));
    const r = await despachar(subs, payload);
    return json({ ok: true, ...r });
  } catch (e) {
    return json({ error: 'Error inesperado', detalle: String(e) }, 500);
  }
});
