import { NextResponse } from "next/server";
import webpush from "web-push";
import { createAdminClient } from "@/lib/supabase-server";

/**
 * Disparo dos avisos do dia.
 *
 * Feita para ser chamada por agendador, uma vez ao dia de manha, com um
 * segredo no cabecalho. Nao usa sessao de usuario porque nao ha usuario: e o
 * relogio que chama.
 *
 * A checagem de assinantes acontece por empresa, e o texto e montado a partir
 * dos alertas que a propria empresa teria visto na agenda — ninguem recebe
 * aviso de dado que nao poderia abrir.
 */

export const dynamic = "force-dynamic";
export const maxDuration = 60;

type Alerta = { tipo: string; gravidade: string; titulo: string; detalhe: string | null };

function configurar() {
  const publica = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY || process.env.VAPID_PUBLIC_KEY;
  const privada = process.env.VAPID_PRIVATE_KEY;
  const contato = process.env.VAPID_SUBJECT || "mailto:contato@ktalogu.com.br";
  if (!publica || !privada) return false;
  webpush.setVapidDetails(contato, publica, privada);
  return true;
}

export async function POST(req: Request) {
  const segredo = process.env.AGENDA_PUSH_SECRET;
  if (!segredo) {
    return NextResponse.json({ error: "AGENDA_PUSH_SECRET nao configurado." }, { status: 500 });
  }
  if (req.headers.get("x-agenda-secret") !== segredo) {
    return NextResponse.json({ error: "Nao autorizado." }, { status: 401 });
  }
  if (!configurar()) {
    return NextResponse.json({ error: "Chaves VAPID nao configuradas." }, { status: 500 });
  }

  const admin = createAdminClient();

  const { data: assinaturas } = await admin
    .from("push_subscriptions")
    .select("id,user_id,company_id,endpoint,p256dh,auth,failures")
    .lt("failures", 5)
    .limit(2000);

  if (!assinaturas?.length) {
    return NextResponse.json({ ok: true, enviados: 0, motivo: "nenhum aparelho registrado" });
  }

  /* Os alertas sao os mesmos que a agenda mostra, buscados no papel de cada
     empresa. Recalcular aqui uma logica paralela seria a receita para o aviso
     dizer uma coisa e a tela dizer outra. */
  const porEmpresa = new Map<string, Alerta[]>();
  for (const a of assinaturas) {
    const empresa = String(a.company_id);
    if (porEmpresa.has(empresa)) continue;
    const { data } = await admin.rpc("get_agenda_alertas_da_empresa", { p_company_id: empresa });
    porEmpresa.set(empresa, (data as Alerta[]) ?? []);
  }

  let enviados = 0;
  let removidos = 0;

  for (const a of assinaturas) {
    const alertas = porEmpresa.get(String(a.company_id)) ?? [];
    if (!alertas.length) continue;

    const criticos = alertas.filter((x) => x.gravidade === "critico");
    const titulo = criticos.length
      ? `${criticos.length} ${criticos.length === 1 ? "urgência" : "urgências"} na agenda`
      : `${alertas.length} ${alertas.length === 1 ? "ponto de atenção" : "pontos de atenção"}`;
    const corpo = alertas.slice(0, 3).map((x) => x.titulo).join(" · ");

    try {
      await webpush.sendNotification(
        { endpoint: String(a.endpoint), keys: { p256dh: String(a.p256dh), auth: String(a.auth) } },
        JSON.stringify({ titulo, corpo, rota: "/dashboard/agenda", tag: "agenda-do-dia" })
      );
      enviados += 1;
      await admin
        .from("push_subscriptions")
        .update({ last_sent_at: new Date().toISOString(), failures: 0 })
        .eq("id", a.id);
    } catch (erro) {
      const status = (erro as { statusCode?: number })?.statusCode;
      /* 404 e 410 querem dizer que o aparelho nao existe mais. Insistir com
         ele so gasta chamada e sujeita a fila. */
      if (status === 404 || status === 410) {
        await admin.from("push_subscriptions").delete().eq("id", a.id);
        removidos += 1;
      } else {
        await admin
          .from("push_subscriptions")
          .update({ failures: Number(a.failures ?? 0) + 1 })
          .eq("id", a.id);
      }
    }
  }

  return NextResponse.json({ ok: true, enviados, removidos, aparelhos: assinaturas.length });
}
