import { createHash, randomBytes } from "node:crypto";

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

import { lerConfiguracoes, preencherMensagem } from "../configuracoes.ts";
import { baseDaLojaSemPedido, listaDeItens } from "../fila-regras.ts";
import { montarEmailDaLoja } from "./email-da-loja";
import { lerLojaDosDigitais } from "./loja";

/*
 * A entrega por e-mail dos produtos digitais.
 *
 * O assunto e a mensagem são os que a loja escreveu em Configurações (com as
 * palavras {{primeiro_nome}}, {{produto}}, {{link_de_acesso}} e {{loja}}).
 * O botão leva à página da entrega na loja com uma chave só deste pedido (o
 * banco guarda só o resumo dela, como as outras chaves). Quem tem o e-mail
 * baixa; a chave não abre o portal do cliente nem outro pedido.
 */

/* Mesma conta da loja (apps/public/src/lib/digitais/compra.ts). */
export function novaChaveDeEntrega(): { chave: string; resumo: string } {
  const chave = randomBytes(32).toString("base64url");
  return { chave, resumo: createHash("sha256").update(chave, "utf8").digest("hex") };
}

/* Um ano: o link do e-mail vale enquanto o acesso valer; a chave em si dura isso. */
const VALIDADE_DA_ENTREGA_MS = 365 * 24 * 60 * 60 * 1000;

/* Os estados em que o acesso existe para o comprador (os outros estão fechados). */
const ABERTOS = ["ativo", "aguardando_arquivo", "aguardando_codigo", "agendado"];

export type EmailDaEntrega = {
  para: string;
  assunto: string;
  html: string;
  texto: string;
  nomeDaLoja: string;
  responderPara: string | null;
  link: string;
  /* A loja quer o lembrete de 24 h para quem não abrir. */
  lembrarEm24h: boolean;
};

export type MontagemDaEntrega = { ok: true; email: EmailDaEntrega } | { ok: false; motivo: string; definitivo: boolean };

/*
 * Por que o e-mail sai:
 * - entrega: a compra (o que ainda espera é explicado: pré-venda, encomenda, código);
 * - lembrete: 24 h depois, para quem não abriu;
 * - codigo: o código que faltava chegou;
 * - arquivo_final: a loja terminou o arquivo feito sob encomenda;
 * - pre_venda: chegou o dia da pré-venda.
 */
export type MotivoDaEntrega = "entrega" | "lembrete" | "codigo" | "arquivo_final" | "pre_venda";

/* "2026-10-14" → "14/10" (a data do calendário, sem fuso). */
function diaDoCalendario(data: string) {
  const [, mes, dia] = data.slice(0, 10).split("-");
  return dia && mes ? `${dia}/${mes}` : data;
}

function dataCurta(iso: string) {
  try {
    return new Intl.DateTimeFormat("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric", timeZone: "America/Sao_Paulo" }).format(
      new Date(iso)
    );
  } catch {
    return iso.slice(0, 10);
  }
}

/* O dia, a hora e quando a sala abre, para o e-mail da vaga na live. */
export function textoDaVagaNaLive(live: { comeca_em: string; espera_min: number; gravar: boolean; gravacao_para: string; status: string }) {
  if (live.status === "encerrada") {
    return live.gravar && live.gravacao_para === "compradores"
      ? "A live já aconteceu: a gravação fica no mesmo link assim que estiver pronta."
      : "A live já aconteceu.";
  }
  let quando = "";
  try {
    quando = new Intl.DateTimeFormat("pt-BR", {
      weekday: "long",
      day: "2-digit",
      month: "long",
      hour: "2-digit",
      minute: "2-digit",
      timeZone: "America/Sao_Paulo",
    }).format(new Date(live.comeca_em));
  } catch {
    quando = live.comeca_em;
  }
  const sala = live.espera_min > 0 ? ` A sala abre ${live.espera_min} minutos antes.` : "";
  const gravacao = live.gravar && live.gravacao_para === "compradores" ? " Não pode ir? A gravação fica para você." : "";
  return `A live é ${quando} (horário de Brasília).${sala} Você recebe um lembrete 1 dia antes e outro 15 minutos antes.${gravacao}`;
}

/** Cria uma chave de entrega para o pedido e devolve o endereço da página. */
export async function criarLinkDaEntrega(
  admin: SupabaseClient,
  params: { lojaId: string; orderId: string; clienteId: string | null; catalogOrderId: string | null; base: string }
): Promise<string | null> {
  const { chave, resumo } = novaChaveDeEntrega();
  const { error } = await admin.from("digital_access_keys").insert({
    user_id: params.lojaId,
    client_id: params.clienteId,
    order_id: params.orderId,
    catalog_order_id: params.catalogOrderId,
    finalidade: "entrega",
    hash: resumo,
    expira_em: new Date(Date.now() + VALIDADE_DA_ENTREGA_MS).toISOString(),
  });
  if (error) return null;
  return `${params.base}/entrega/${chave}`;
}

/**
 * Monta o e-mail da entrega de um pedido (e cria a chave do link). `definitivo`
 * diz se não adianta tentar de novo (pedido cancelado, nada para entregar).
 * `lembrete`: o e-mail de 24 h para quem ainda não abriu.
 */
export async function montarEntrega(
  admin: SupabaseClient,
  params: { lojaId: string; orderId: string; destino: string; catalogOrderId?: string | null; lembrete?: boolean; motivo?: MotivoDaEntrega }
): Promise<MontagemDaEntrega> {
  const { lojaId, orderId, destino } = params;
  const motivo: MotivoDaEntrega = params.motivo ?? (params.lembrete ? "lembrete" : "entrega");
  const para = String(destino || "").trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(para)) return { ok: false, motivo: "e-mail inválido", definitivo: true };

  const { data: pedido } = await admin
    .from("orders")
    .select("id,number,status,client_id,user_id")
    .eq("id", orderId)
    .eq("user_id", lojaId)
    .maybeSingle();
  const linha = pedido as { id: string; number: number | null; status: string; client_id: string | null } | null;
  if (!linha) return { ok: false, motivo: "pedido não encontrado", definitivo: true };
  if (linha.status === "canceled") return { ok: false, motivo: "pedido cancelado", definitivo: true };

  const { data: acessos } = await admin
    .from("digital_entitlements")
    .select("status,expira_em,catalog_order_id,ultimo_acesso_em,libera_em,entregar_ate,products(name),digital_deliverables(titulo,posicao,tipo,live_id)")
    .eq("order_id", orderId)
    .eq("user_id", lojaId);
  const todos = (acessos ?? []) as unknown as Array<{
    status: string;
    expira_em: string | null;
    catalog_order_id: string | null;
    ultimo_acesso_em: string | null;
    libera_em: string | null;
    entregar_ate: string | null;
    products: { name: string } | null;
    digital_deliverables: { titulo: string; posicao: number; tipo?: string | null; live_id?: string | null } | null;
  }>;
  const lista = todos.filter((a) => ABERTOS.includes(a.status));
  /* Só curso: o e-mail fala de assistir, não de baixar. */
  const soCurso = lista.every((a) => a.digital_deliverables?.tipo === "curso");
  /* Só código ou licença: o e-mail fala de abrir e copiar o código, não de baixar. */
  const soCodigo = lista.every((a) => a.digital_deliverables?.tipo === "codigos");
  /* Só live: o e-mail fala da vaga garantida, do dia e da hora. */
  const soLive = lista.length > 0 && lista.every((a) => a.digital_deliverables?.tipo === "live");
  if (!lista.length) return { ok: false, motivo: "nenhum acesso aberto neste pedido", definitivo: true };
  /* O código e o arquivo final só avisam o que já abriu. */
  if ((motivo === "codigo" || motivo === "arquivo_final") && !lista.some((a) => a.status === "ativo")) {
    return { ok: false, motivo: "nada novo liberado neste pedido", definitivo: true };
  }

  /* A live tem os lembretes dela (1 dia e 15 minutos antes): o de 24 h não sai. */
  if (motivo === "lembrete" && soLive) return { ok: false, motivo: "a live tem lembretes próprios", definitivo: true };

  if (motivo === "lembrete") {
    /* Já baixou ou abriu o link do e-mail: o lembrete não sai. */
    if (todos.some((a) => a.ultimo_acesso_em)) return { ok: false, motivo: "o comprador já acessou", definitivo: true };
    const { count } = await admin
      .from("digital_access_keys")
      .select("id", { count: "exact", head: true })
      .eq("order_id", orderId)
      .eq("finalidade", "entrega")
      .not("usada_em", "is", null);
    if ((count ?? 0) > 0) return { ok: false, motivo: "o comprador já abriu a entrega", definitivo: true };
  }

  const [loja, cliente, perfil, ajustes, compra] = await Promise.all([
    lerLojaDosDigitais(admin, lojaId),
    linha.client_id
      ? admin.from("clients").select("name,email").eq("id", linha.client_id).maybeSingle()
      : Promise.resolve({ data: null }),
    admin.from("profiles").select("company_email,email").eq("id", lojaId).maybeSingle(),
    admin.from("digital_settings").select("config").eq("user_id", lojaId).maybeSingle(),
    /* O número que o comprador viu na tela é o do pedido da loja. */
    admin.from("catalog_orders").select("number").eq("approved_order_id", orderId).eq("user_id", lojaId).order("created_at", { ascending: false }).limit(1),
  ]);
  const numeroDaCompra = ((compra.data ?? []) as Array<{ number: number | null }>)[0]?.number ?? linha.number;
  const base = baseDaLojaSemPedido(loja, process.env);
  if (!base) return { ok: false, motivo: "a loja não tem endereço público", definitivo: false };
  const config = lerConfiguracoes((ajustes.data as { config?: unknown } | null)?.config);

  const catalogOrderId = params.catalogOrderId ?? lista.find((a) => a.catalog_order_id)?.catalog_order_id ?? null;
  const link = await criarLinkDaEntrega(admin, { lojaId, orderId, clienteId: linha.client_id, catalogOrderId, base });
  if (!link) return { ok: false, motivo: "não foi possível criar o link", definitivo: false };

  const membros = `${base}/membros`;
  const nomeDaArea = config.area.nome || loja.nome;
  const nomeDoCliente = String((cliente.data as { name?: string | null } | null)?.name || "").trim();
  const emailDoCadastro = String((cliente.data as { email?: string | null } | null)?.email || "").trim().toLowerCase();
  const primeiroNome = nomeDoCliente.split(/\s+/)[0] || "";
  const produtos = Array.from(new Set(lista.map((a) => a.products?.name).filter((n): n is string => Boolean(n))));
  const nomeDosProdutos = listaDeItens(produtos, 3) || "sua compra";
  const itens = listaDeItens(
    lista
      .slice()
      .sort((a, b) => (a.digital_deliverables?.posicao ?? 0) - (b.digital_deliverables?.posicao ?? 0))
      .map((a) => a.digital_deliverables?.titulo ?? "")
  );
  /* O que ainda espera, com a data quando há. */
  const ativos = lista.filter((a) => a.status === "ativo");
  const agendados = lista.filter((a) => a.status === "agendado");
  const encomendas = lista.filter((a) => a.status === "aguardando_arquivo" && a.digital_deliverables?.tipo === "encomenda");
  const codigosEsperando = lista.filter((a) => a.status === "aguardando_codigo");
  const outrosPreparando = lista.filter(
    (a) => a.status !== "ativo" && !agendados.includes(a) && !encomendas.includes(a) && !codigosEsperando.includes(a)
  );
  const liberaEm = agendados.map((a) => a.libera_em).filter((d): d is string => Boolean(d)).sort()[0] ?? null;
  const entregarAte = encomendas.map((a) => a.entregar_ate).filter((d): d is string => Boolean(d)).sort()[0] ?? null;
  const soEsperando = !ativos.length;
  const idDaLive = soLive ? lista.find((a) => a.digital_deliverables?.live_id)?.digital_deliverables?.live_id ?? null : null;
  const live = idDaLive
    ? ((await admin.from("live_salas").select("comeca_em,espera_min,gravar,gravacao_para,status").eq("id", idDaLive).eq("user_id", lojaId).maybeSingle())
        .data as { comeca_em: string; espera_min: number; gravar: boolean; gravacao_para: string; status: string } | null)
    : null;
  const prazos = lista.map((a) => a.expira_em).filter((d): d is string => Boolean(d)).sort();

  const palavras = { primeiro_nome: primeiroNome || "tudo bem", produto: nomeDosProdutos, link_de_acesso: link, loja: loja.nome };
  const assuntoDaLoja = preencherMensagem(config.entrega.assunto, palavras).replace(/\s+/g, " ").trim().slice(0, 140);
  const mensagemDaLoja = preencherMensagem(config.entrega.mensagem, palavras)
    .split(/\n+/)
    .map((p) => p.trim())
    .filter(Boolean);

  const avisosDaEspera = [
    agendados.length
      ? liberaEm
        ? `Pré-venda: ${soCurso ? "o conteúdo abre" : "libera"} em ${dataCurta(liberaEm)}. Nesse dia você recebe outro e-mail e encontra tudo no mesmo link.`
        : "Pré-venda: libera na data do lançamento. Você recebe outro e-mail nesse dia."
      : "",
    encomendas.length
      ? entregarAte
        ? `A loja está fazendo o seu: entrega até ${diaDoCalendario(entregarAte)}. Você recebe outro e-mail quando ficar pronto.`
        : "A loja está fazendo o seu. Você recebe outro e-mail quando ficar pronto."
      : "",
    codigosEsperando.length ? "Seu código chega em breve: a loja está repondo. Você recebe outro e-mail quando ele chegar." : "",
    outrosPreparando.length ? "Alguns itens ainda estão sendo preparados pela loja. Eles aparecem no mesmo link assim que ficarem prontos." : "",
  ].filter(Boolean);

  /* O começo do e-mail: a mensagem da loja vale para a entrega de verdade; o que só espera tem o texto dele. */
  const abertura =
    motivo === "lembrete"
      ? [`${primeiroNome ? `${primeiroNome}, v` : "V"}ocê ainda não abriu ${nomeDosProdutos}. Seu acesso continua liberado: é só entrar pelo botão abaixo.`]
      : motivo === "codigo"
        ? [`${primeiroNome ? `${primeiroNome}, o` : "O"} código de ${nomeDosProdutos} chegou. Abra pelo botão para ver e copiar.`]
        : motivo === "arquivo_final"
          ? [`${primeiroNome ? `${primeiroNome}, a` : "A"} loja terminou o seu ${nomeDosProdutos}. Baixe pelo botão abaixo.`]
          : motivo === "pre_venda"
            ? [`${primeiroNome ? `${primeiroNome}, c` : "C"}hegou o dia: ${nomeDosProdutos} foi liberado. É só entrar pelo botão abaixo.`]
            : soEsperando
              ? [`${primeiroNome ? `Oi, ${primeiroNome}! ` : ""}Obrigado pela compra de ${nomeDosProdutos} na ${loja.nome}.`]
              : mensagemDaLoja;

  const paragrafos = [
    ...abertura,
    itens && !soEsperando ? `Você recebeu: ${itens}.` : "",
    ...(motivo === "entrega" || motivo === "lembrete" ? avisosDaEspera : []),
    live
      ? textoDaVagaNaLive(live)
      : prazos.length
      ? `O acesso vale até ${dataCurta(prazos[0])}.`
      : soEsperando
        ? ""
        : soCurso
          ? "O acesso não tem prazo: assista quantas vezes quiser, de onde parou."
          : soCodigo
            ? "O acesso não tem prazo: o seu código fica guardado, é só abrir pelo botão quando precisar."
            : "O acesso não tem prazo: baixe quantas vezes precisar.",
    numeroDaCompra ? `Pedido #${numeroDaCompra} na ${loja.nome}.` : "",
  ].filter(Boolean);

  const titulo =
    motivo === "lembrete"
      ? "Sua compra está esperando por você"
      : motivo === "codigo"
        ? "Seu código chegou"
        : motivo === "arquivo_final"
          ? "Ficou pronto!"
          : motivo === "pre_venda"
            ? "Chegou o dia!"
            : soEsperando && agendados.length
              ? "Sua pré-venda está garantida"
              : soLive && !soEsperando
                ? primeiroNome
                  ? `${primeiroNome}, sua vaga está garantida!`
                  : "Sua vaga está garantida!"
              : soEsperando && encomendas.length
                ? "Recebemos sua encomenda"
                : soEsperando
                  ? "Recebemos sua compra"
                  : primeiroNome
                    ? `Pronto, ${primeiroNome}! Sua compra chegou.`
                    : "Pronto! Sua compra chegou.";
  const resumo =
    motivo === "lembrete"
      ? "Seu acesso continua esperando por você."
      : motivo === "codigo"
        ? "O código que faltava já está na sua compra."
        : motivo === "arquivo_final"
          ? "O arquivo feito para você já está na sua compra."
          : soEsperando
            ? "Guarde este e-mail: é por ele que você acessa a sua compra."
            : soLive
              ? "Sua vaga na live está garantida. Guarde este e-mail."
            : soCurso
              ? "Seu acesso está liberado. Assista quando quiser."
              : soCodigo
                ? "Seu código está liberado. Copie quando precisar."
                : "Seu acesso está liberado. Baixe quando quiser.";
  const textoDoBotao =
    motivo === "codigo" || (soCodigo && !soEsperando)
      ? "Ver meu código"
      : motivo === "arquivo_final"
        ? "Baixar meu arquivo"
        : soEsperando
          ? "Ver minha compra"
          : soLive
            ? "Ver a live"
            : "Acessar minha compra";

  const conteudo = montarEmailDaLoja({
    loja: { nome: loja.nome, logo: loja.logo, cor: loja.cor },
    resumo,
    titulo,
    paragrafos,
    botao: { texto: textoDoBotao, link },
    observacao:
      emailDoCadastro && emailDoCadastro === para
        ? `Este link é só seu: não encaminhe este e-mail. Também dá para achar tudo em ${nomeDaArea === loja.nome ? "Minhas compras" : nomeDaArea} (${membros}), entrando com este e-mail.`
        : soLive
          ? "Este link é só seu: não encaminhe este e-mail. É por ele que você entra na live."
        : soCurso
          ? "Este link é só seu: não encaminhe este e-mail. Guarde-o para voltar ao conteúdo quando quiser."
          : soCodigo
            ? "Este link é só seu: não encaminhe este e-mail. Guarde-o para ver o seu código de novo quando precisar."
            : "Este link é só seu: não encaminhe este e-mail. Guarde-o para baixar de novo quando quiser.",
  });

  const perfilDaLoja = (perfil.data ?? {}) as { company_email?: string | null; email?: string | null };
  return {
    ok: true,
    email: {
      para,
      assunto: (motivo === "lembrete"
        ? `Lembrete: ${assuntoDaLoja || `seu acesso a ${nomeDosProdutos}`}`
        : motivo === "codigo"
          ? `Seu código chegou: ${nomeDosProdutos}`
          : motivo === "arquivo_final"
            ? `Ficou pronto: ${nomeDosProdutos}`
            : motivo === "pre_venda"
              ? `Liberado: ${nomeDosProdutos}`
              : soLive && !soEsperando
                ? `Vaga garantida: ${nomeDosProdutos}`
              : soEsperando && agendados.length
                ? `Pré-venda garantida: ${nomeDosProdutos}`
                : soEsperando && encomendas.length
                  ? `Encomenda recebida: ${nomeDosProdutos}`
                  : soEsperando
                    ? `Compra recebida: ${nomeDosProdutos}`
                    : assuntoDaLoja || `Seu acesso: ${nomeDosProdutos}`
      ).slice(0, 160),
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja: loja.nome,
      responderPara: String(perfilDaLoja.company_email || perfilDaLoja.email || "").trim() || null,
      link,
      /* O lembrete de 24 h é para quem recebeu e não abriu: não para quem só espera. */
      lembrarEm24h: (motivo === "entrega" || motivo === "pre_venda") && !soEsperando && config.entrega.reenviarEm24h,
    },
  };
}

/** Agenda o lembrete de 24 h (uma vez por pedido). */
export async function agendarLembrete(admin: SupabaseClient, params: { lojaId: string; orderId: string; destino: string; catalogOrderId: string | null }) {
  await admin.from("digital_outbox").upsert(
    {
      user_id: params.lojaId,
      canal: "email",
      tipo: "lembrete",
      destino: params.destino,
      dados: { order_id: params.orderId, catalog_order_id: params.catalogOrderId },
      chave_unica: `lembrete:${params.orderId}`,
      proxima_em: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
    },
    { onConflict: "chave_unica", ignoreDuplicates: true }
  );
}

/**
 * O aviso do acesso de cortesia (sem pedido): a pessoa entra em Minhas compras
 * com o próprio e-mail e um código, sem senha.
 */
export async function montarAvisoDeCortesia(
  admin: SupabaseClient,
  params: { lojaId: string; clienteId: string; produtoId: string; destino: string }
): Promise<MontagemDaEntrega> {
  const { lojaId, clienteId, produtoId } = params;
  const para = String(params.destino || "").trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(para)) return { ok: false, motivo: "e-mail inválido", definitivo: true };

  const { data: acessos } = await admin
    .from("digital_entitlements")
    .select("status,expira_em,products(name),digital_deliverables(titulo,posicao)")
    .eq("user_id", lojaId)
    .eq("client_id", clienteId)
    .eq("product_id", produtoId)
    .eq("origem", "cortesia");
  const lista = ((acessos ?? []) as unknown as Array<{
    status: string;
    expira_em: string | null;
    products: { name: string } | null;
    digital_deliverables: { titulo: string; posicao: number } | null;
  }>).filter((a) => ABERTOS.includes(a.status));
  if (!lista.length) return { ok: false, motivo: "o acesso de cortesia não está aberto", definitivo: true };

  const [loja, cliente, perfil, ajustes] = await Promise.all([
    lerLojaDosDigitais(admin, lojaId),
    admin.from("clients").select("name,email").eq("id", clienteId).eq("user_id", lojaId).maybeSingle(),
    admin.from("profiles").select("company_email,email").eq("id", lojaId).maybeSingle(),
    admin.from("digital_settings").select("config").eq("user_id", lojaId).maybeSingle(),
  ]);
  const nomeDaArea = lerConfiguracoes((ajustes.data as { config?: unknown } | null)?.config).area.nome || "Minhas compras";
  const base = baseDaLojaSemPedido(loja, process.env);
  if (!base) return { ok: false, motivo: "a loja não tem endereço público", definitivo: false };
  const membros = `${base}/membros`;
  const emailDoCadastro = String((cliente.data as { email?: string | null } | null)?.email || "").trim().toLowerCase();
  /* A entrada é pelo e-mail do cadastro: avisar outro e-mail levaria a uma porta fechada. */
  if (emailDoCadastro !== para) return { ok: false, motivo: "o e-mail não é o do cadastro", definitivo: true };

  const produto = lista[0].products?.name || "seu acesso";
  const primeiroNome = String((cliente.data as { name?: string | null } | null)?.name || "").trim().split(/\s+/)[0] || "";
  const itens = listaDeItens(
    lista
      .slice()
      .sort((a, b) => (a.digital_deliverables?.posicao ?? 0) - (b.digital_deliverables?.posicao ?? 0))
      .map((a) => a.digital_deliverables?.titulo ?? "")
  );
  const prazos = lista.map((a) => a.expira_em).filter((d): d is string => Boolean(d)).sort();
  const conteudo = montarEmailDaLoja({
    loja: { nome: loja.nome, logo: loja.logo, cor: loja.cor },
    resumo: `A ${loja.nome} liberou ${produto} para você.`,
    titulo: `Você ganhou acesso a ${produto}`,
    paragrafos: [
      primeiroNome ? `Olá, ${primeiroNome}!` : "Olá!",
      `A ${loja.nome} liberou para você: ${produto}.`,
      itens ? `Você recebeu: ${itens}.` : "",
      prazos.length ? `O acesso vale até ${dataCurta(prazos[0])}.` : "O acesso não tem prazo.",
    ].filter(Boolean),
    botao: { texto: `Entrar em ${nomeDaArea}`, link: membros },
    observacao: "Entre com este e-mail: um código chega na hora, sem senha.",
  });
  const perfilDaLoja = (perfil.data ?? {}) as { company_email?: string | null; email?: string | null };
  return {
    ok: true,
    email: {
      para,
      assunto: `${loja.nome} liberou para você: ${produto}`.slice(0, 160),
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja: loja.nome,
      responderPara: String(perfilDaLoja.company_email || perfilDaLoja.email || "").trim() || null,
      link: membros,
      lembrarEm24h: false,
    },
  };
}

/**
 * "Continue de onde parou": o aluno que não estuda há 30 dias (no máximo um
 * por mês; a loja desliga em Configurações). Leva ao curso na área de
 * membros, onde se entra com o e-mail e um código, sem senha.
 */
export async function montarLembreteDoCurso(
  admin: SupabaseClient,
  params: { lojaId: string; clienteId: string; produtoId: string; destino: string }
): Promise<MontagemDaEntrega> {
  const { lojaId, clienteId, produtoId } = params;
  const para = String(params.destino || "").trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(para)) return { ok: false, motivo: "e-mail inválido", definitivo: true };

  const [acesso, produto, aulas, feitas, loja, cliente, perfil, ajustes] = await Promise.all([
    admin
      .from("digital_entitlements")
      .select("id,status,expira_em,digital_deliverables!inner(tipo)")
      .eq("user_id", lojaId)
      .eq("client_id", clienteId)
      .eq("product_id", produtoId)
      .eq("digital_deliverables.tipo", "curso")
      .eq("status", "ativo")
      .limit(1),
    admin.from("products").select("name").eq("id", produtoId).eq("user_id", lojaId).maybeSingle(),
    admin
      .from("digital_course_lessons")
      .select("id", { count: "exact", head: true })
      .eq("product_id", produtoId)
      .eq("user_id", lojaId)
      .eq("publicada", true)
      .is("apagado_em", null),
    admin
      .from("digital_course_progress")
      .select("lesson_id", { count: "exact", head: true })
      .eq("client_id", clienteId)
      .eq("product_id", produtoId)
      .not("concluida_em", "is", null),
    lerLojaDosDigitais(admin, lojaId),
    admin.from("clients").select("name").eq("id", clienteId).eq("user_id", lojaId).maybeSingle(),
    admin.from("profiles").select("company_email,email").eq("id", lojaId).maybeSingle(),
    admin.from("digital_settings").select("config").eq("user_id", lojaId).maybeSingle(),
  ]);
  const linha = ((acesso.data ?? []) as Array<{ expira_em: string | null }>)[0];
  if (!linha || (linha.expira_em && new Date(linha.expira_em).getTime() < Date.now())) return { ok: false, motivo: "o acesso ao conteúdo fechou", definitivo: true };
  const curso = String((produto.data as { name?: string | null } | null)?.name || "").trim();
  if (!curso) return { ok: false, motivo: "o conteúdo não existe mais", definitivo: true };
  const total = aulas.count ?? 0;
  const concluidas = Math.min(total, feitas.count ?? 0);
  if (total && concluidas >= total) return { ok: false, motivo: "o cliente terminou o conteúdo", definitivo: true };
  const config = lerConfiguracoes((ajustes.data as { config?: unknown } | null)?.config);
  if (config.lembretes.alunosParados === false) return { ok: false, motivo: "a loja desligou os lembretes", definitivo: true };

  const base = baseDaLojaSemPedido(loja, process.env);
  if (!base) return { ok: false, motivo: "a loja não tem endereço público", definitivo: false };
  const nomeDaArea = config.area.nome || loja.nome;
  const primeiroNome = String((cliente.data as { name?: string | null } | null)?.name || "").trim().split(/\s+/)[0] || "";
  const conteudo = montarEmailDaLoja({
    loja: { nome: loja.nome, logo: loja.logo, cor: loja.cor },
    resumo: "Continue de onde parou.",
    titulo: primeiroNome ? `${primeiroNome}, seu conteúdo está esperando` : "Seu conteúdo está esperando",
    paragrafos: [
      `Faz um tempo que você não assiste ${curso}.${total ? ` Você já concluiu ${concluidas} de ${total} ${total === 1 ? "vídeo" : "vídeos"}.` : ""} Que tal continuar hoje? O conteúdo volta de onde você parou.`,
      `Para entrar, use este e-mail em ${nomeDaArea}: chega um código, sem senha.`,
    ],
    botao: { texto: "Continuar assistindo", link: `${base}/membros/curso/${produtoId}` },
    observacao: "Você recebe no máximo um lembrete destes por mês.",
  });
  const perfilDaLoja = (perfil.data ?? {}) as { company_email?: string | null; email?: string | null };
  return {
    ok: true,
    email: {
      para,
      assunto: `Continue de onde parou: ${curso}`.slice(0, 160),
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja: loja.nome,
      responderPara: String(perfilDaLoja.company_email || perfilDaLoja.email || "").trim() || null,
      link: `${base}/membros/curso/${produtoId}`,
      lembrarEm24h: false,
    },
  };
}

/** O certificado ficou pronto: o link leva à página pública dele, com o PDF. */
export async function montarAvisoDoCertificado(
  admin: SupabaseClient,
  params: { lojaId: string; certificadoId: string; destino: string }
): Promise<MontagemDaEntrega> {
  const para = String(params.destino || "").trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(para)) return { ok: false, motivo: "e-mail inválido", definitivo: true };
  const [certificado, loja, perfil] = await Promise.all([
    admin
      .from("digital_certificates")
      .select("codigo,nome_do_aluno,curso,carga_horaria_min,revogado_em")
      .eq("id", params.certificadoId)
      .eq("user_id", params.lojaId)
      .maybeSingle(),
    lerLojaDosDigitais(admin, params.lojaId),
    admin.from("profiles").select("company_email,email").eq("id", params.lojaId).maybeSingle(),
  ]);
  const linha = certificado.data as { codigo: string; nome_do_aluno: string; curso: string; carga_horaria_min: number; revogado_em: string | null } | null;
  if (!linha || linha.revogado_em) return { ok: false, motivo: "o certificado não vale mais", definitivo: true };
  const base = baseDaLojaSemPedido(loja, process.env);
  if (!base) return { ok: false, motivo: "a loja não tem endereço público", definitivo: false };
  const link = `${base}/certificado/${encodeURIComponent(linha.codigo)}`;
  const primeiroNome = linha.nome_do_aluno.trim().split(/\s+/)[0] || "";
  const horas = Math.round((linha.carga_horaria_min / 60) * 10) / 10;
  const conteudo = montarEmailDaLoja({
    loja: { nome: loja.nome, logo: loja.logo, cor: loja.cor },
    resumo: "Seu certificado está pronto.",
    titulo: primeiroNome ? `Parabéns, ${primeiroNome}!` : "Parabéns!",
    paragrafos: [
      `Você concluiu ${linha.curso}${horas ? ` (${String(horas).replace(".", ",")} ${horas === 1 ? "hora" : "horas"})` : ""}. Seu certificado está pronto para baixar em PDF.`,
      `Ele tem um código que qualquer pessoa confere no endereço da loja: ${linha.codigo}.`,
    ],
    botao: { texto: "Ver meu certificado", link },
    observacao: "Guarde este e-mail: o link do certificado vale para sempre.",
  });
  const perfilDaLoja = (perfil.data ?? {}) as { company_email?: string | null; email?: string | null };
  return {
    ok: true,
    email: {
      para,
      assunto: `Seu certificado: ${linha.curso}`.slice(0, 160),
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja: loja.nome,
      responderPara: String(perfilDaLoja.company_email || perfilDaLoja.email || "").trim() || null,
      link,
      lembrarEm24h: false,
    },
  };
}
