import type { SupabaseClient } from "@supabase/supabase-js";
import webpush from "web-push";

/*
  Aviso de mensagem no celular da loja.

  Quando o cliente escreve, quem precisa saber e a equipe — e ela quase nunca
  esta com o Chats aberto. Os aparelhos sao os mesmos ja registrados para os
  lembretes da agenda: quem ligou o aviso uma vez recebe tudo.

  Falhar aqui nao pode derrubar o envio da mensagem: o aviso e pressa, a
  mensagem e o que importa.
*/

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 avisarLojaPorPush(
  admin: SupabaseClient,
  params: { tenantId?: string | null; titulo: string; corpo: string; rota: string; tag?: string }
) {
  if (!params.tenantId || !configurar()) return { enviados: 0 };

  const icone = await iconeDaLoja(admin, params.tenantId);

  const { data: aparelhos } = await admin
    .from("push_subscriptions")
    .select("id,endpoint,p256dh,auth,failures")
    .eq("company_id", params.tenantId)
    .lt("failures", 5)
    .limit(50);

  let enviados = 0;
  for (const aparelho of aparelhos ?? []) {
    try {
      await webpush.sendNotification(
        {
          endpoint: String(aparelho.endpoint),
          keys: { p256dh: String(aparelho.p256dh), auth: String(aparelho.auth) },
        },
        JSON.stringify({
          titulo: params.titulo,
          corpo: params.corpo,
          rota: params.rota,
          tag: params.tag || "ktalogu-conversa",
          icone,
        })
      );
      enviados += 1;
      await admin
        .from("push_subscriptions")
        .update({ last_sent_at: new Date().toISOString(), failures: 0 })
        .eq("id", aparelho.id);
    } catch (erro) {
      const status = (erro as { statusCode?: number })?.statusCode;
      if (status === 404 || status === 410) {
        await admin.from("push_subscriptions").delete().eq("id", aparelho.id);
      } else {
        await admin
          .from("push_subscriptions")
          .update({ failures: Number(aparelho.failures ?? 0) + 1 })
          .eq("id", aparelho.id);
      }
    }
  }

  return { enviados };
}

/*
  O icone do aviso e o da loja, e nao o do Ktalogu — quem recebe reconhece de
  quem e o recado pela figurinha antes de ler.
*/
const iconesPorLoja = new Map<string, { valor: string | null; em: number }>();
const VALIDADE_DO_ICONE_MS = 5 * 60 * 1000;

export async function iconeDaLoja(admin: SupabaseClient, tenantId?: string | null) {
  if (!tenantId) return null;

  const guardado = iconesPorLoja.get(tenantId);
  if (guardado && Date.now() - guardado.em < VALIDADE_DO_ICONE_MS) return guardado.valor;

  const { data } = await admin
    .from("profiles")
    .select("catalog_favicon_url,catalog_logo_url,logo_url")
    .eq("id", tenantId)
    .maybeSingle();

  const perfil = data as
    | { catalog_favicon_url?: string | null; catalog_logo_url?: string | null; logo_url?: string | null }
    | null;

  const escolhido =
    [perfil?.catalog_favicon_url, perfil?.catalog_logo_url, perfil?.logo_url]
      .map((valor) => String(valor || "").trim())
      .find((valor) => valor.startsWith("http")) || null;

  iconesPorLoja.set(tenantId, { valor: escolhido, em: Date.now() });
  return escolhido;
}

/*
  Venda aprovada na loja online.

  A loja quer saber duas coisas quando o dinheiro entra: como foi pago e quanto
  foi. O resto espera ela abrir o sistema.
*/
export async function avisarVendaAprovada(
  admin: SupabaseClient,
  params: {
    tenantId?: string | null;
    valor: number;
    metodo?: string | null;
    numero?: number | string | null;
    cliente?: string | null;
    rota?: string;
  }
) {
  if (!params.tenantId || !configurar()) return { enviados: 0 };

  const dinheiro = new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(
    Number(params.valor || 0)
  );
  const comoFoiPaga = rotuloDoMeio(params.metodo);
  const titulo = comoFoiPaga ? `Venda aprovada no ${comoFoiPaga}` : "Venda aprovada";
  const detalhe = [params.numero ? `Pedido #${params.numero}` : null, params.cliente || null, "Loja online"]
    .filter(Boolean)
    .join(" · ");

  const icone = await iconeDaLoja(admin, params.tenantId);

  const { data: aparelhos } = await admin
    .from("push_subscriptions")
    .select("id,endpoint,p256dh,auth,failures")
    .eq("company_id", params.tenantId)
    .lt("failures", 5)
    .limit(50);

  let enviados = 0;
  for (const aparelho of aparelhos ?? []) {
    try {
      await webpush.sendNotification(
        {
          endpoint: String(aparelho.endpoint),
          keys: { p256dh: String(aparelho.p256dh), auth: String(aparelho.auth) },
        },
        JSON.stringify({
          titulo,
          corpo: `${dinheiro}
${detalhe}`,
          rota: params.rota || "/dashboard/catalog/orders",
          tag: `venda-${params.numero || Date.now()}`,
          icone,
        })
      );
      enviados += 1;
      await admin
        .from("push_subscriptions")
        .update({ last_sent_at: new Date().toISOString(), failures: 0 })
        .eq("id", aparelho.id);
    } catch (erro) {
      const status = (erro as { statusCode?: number })?.statusCode;
      if (status === 404 || status === 410) {
        await admin.from("push_subscriptions").delete().eq("id", aparelho.id);
      } else {
        await admin
          .from("push_subscriptions")
          .update({ failures: Number(aparelho.failures ?? 0) + 1 })
          .eq("id", aparelho.id);
      }
    }
  }

  return { enviados };
}

/* Pix, cartao, boleto: o nome que a pessoa usa no balcao. */
export function rotuloDoMeio(metodo?: string | null) {
  const chave = String(metodo || "").toLowerCase();
  if (!chave) return "";
  if (chave.includes("pix") || chave === "bank_transfer") return "Pix";
  if (chave.includes("credit")) return "cartão de crédito";
  if (chave.includes("debit")) return "cartão de débito";
  if (chave.includes("card") || chave.includes("cartao")) return "cartão";
  if (chave.includes("boleto") || chave.includes("ticket")) return "boleto";
  return "";
}
