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

import { lerVencimento, statusLibera } from "@/lib/assinatura";
import { OFERTAS_KTALOGU, PRODUTO_KTALOGU, type AvisoCakto } from "@/lib/assinatura-cakto";
import {
  acontecimentoParaODono,
  lembrarDoPix,
  lembreteDeCarrinho,
  primeiroPasso,
  TITULO_PARA_O_DONO,
  type Abandono,
  type PrimeiroPasso,
} from "@/lib/automacoes-da-assinatura";
import { diaEmBrasilia } from "@/lib/avisos-da-assinatura";
import { enviarUmaVez } from "@/lib/avisos-da-assinatura-servidor";
import { emailConfigurado, montarEmail } from "@/lib/email-transacional";

/**
 * As automações da assinatura (30/09/2026): carrinho abandonado, Pix gerado e
 * não pago, primeiros passos e o aviso ao dono da plataforma. As regras moram
 * em `lib/automacoes-da-assinatura`; aqui é ler o banco e mandar. Tudo sai uma
 * vez só (`enviarUmaVez`) e nada disso derruba o aviso da Cakto que o chamou.
 */

type Admin = SupabaseClient;

const PAINEL = "https://admin.ktalogu.com.br";
const DIA_MS = 24 * 60 * 60 * 1000;

const moeda = (valor: number) => valor.toLocaleString("pt-BR", { style: "currency", currency: "BRL" });

function dataCurta(momento: Date) {
  const [ano, mes, dia] = diaEmBrasilia(momento).split("-");
  return `${dia}/${mes}/${ano}`;
}

function planoDaOferta(ofertaId: string | null) {
  const oferta = ofertaId ? OFERTAS_KTALOGU[ofertaId] : undefined;
  return oferta ? `${oferta.plano === "anual" ? "Anual" : "Mensal"} · ${moeda(oferta.preco)}${oferta.plano === "anual" ? " por ano" : " por mês"}` : null;
}

/* ------------------------------------------------------------------ */
/* Carrinho abandonado                                                 */
/* ------------------------------------------------------------------ */

export async function guardarAbandono(admin: Admin, abandono: Abandono) {
  const { error } = await admin.from("carrinhos_abandonados").upsert(
    {
      email: abandono.email,
      nome: abandono.nome,
      oferta_id: abandono.ofertaId,
      checkout_url: abandono.checkoutUrl,
      abandonado_em: abandono.abandonadoEm.toISOString(),
    },
    { onConflict: "email,oferta_id,abandonado_em", ignoreDuplicates: true }
  );
  if (error) throw new Error(`Não foi possível guardar o carrinho: ${error.message}`);
}

/* Comprou depois de abandonar? Um pagamento aprovado (de qualquer plano da
   Ktalogu) a partir de 10 minutos antes do abandono conta como convertido. */
async function comprouDepois(admin: Admin, email: string, abandonadoEm: Date) {
  const { data } = await admin
    .from("pagamentos_cakto")
    .select("pedido_id")
    .eq("email", email)
    .eq("status", "paid")
    .gte("criado_em", new Date(abandonadoEm.getTime() - 10 * 60 * 1000).toISOString())
    .limit(1);
  return Boolean(data?.length);
}

function emailDeCarrinho(tipo: "carrinho-1h" | "carrinho-24h", linha: { nome: string | null; oferta_id: string | null; checkout_url: string | null }) {
  const primeiroNome = (linha.nome ?? "").split(" ")[0];
  const link = linha.checkout_url || `https://pay.cakto.com.br/${linha.oferta_id || "gvndd3a"}`;
  const plano = planoDaOferta(linha.oferta_id);
  if (tipo === "carrinho-1h") {
    return {
      assunto: `${primeiroNome ? `${primeiroNome}, faltou` : "Faltou"} pouco para ativar sua Ktalogu`,
      ...montarEmail({
        resumo: "Seu cadastro ficou pela metade. Continue de onde parou em um clique.",
        etiqueta: "Seu cadastro",
        titulo: "Faltou pouco para ativar sua Ktalogu",
        paragrafos: [
          `${primeiroNome ? `Oi, ${primeiroNome}! ` : ""}Você começou a assinar a Ktalogu e parou no pagamento. Acontece: guardamos tudo para você continuar de onde parou.`,
          "Com a Ktalogu você organiza orçamentos, pedidos e produção num lugar só, e ainda ganha uma loja virtual pronta para vender.",
        ],
        linhas: plano ? [{ rotulo: "Plano escolhido", valor: plano }] : undefined,
        botao: { texto: "Continuar de onde parei", link },
      }),
    };
  }
  return {
    assunto: "Ainda dá tempo de começar com a Ktalogu",
    ...montarEmail({
      resumo: "Ficou alguma dúvida? Fale com a gente no WhatsApp ou conclua em um clique.",
      etiqueta: "Seu cadastro",
      titulo: "Ainda dá tempo de começar",
      paragrafos: [
        "Ontem você começou a assinar a Ktalogu e não concluiu. Se ficou alguma dúvida sobre o sistema, a forma de pagamento ou o plano, chame a gente no WhatsApp: respondemos rápido.",
        "Se já estiver decidido, é só continuar pelo botão abaixo. Leva menos de um minuto.",
      ],
      linhas: plano ? [{ rotulo: "Plano escolhido", valor: plano }] : undefined,
      botao: { texto: "Concluir minha assinatura", link },
    }),
  };
}

export async function enviarLembretesDeCarrinho(admin: Admin, agora = new Date()) {
  if (!emailConfigurado()) return 0;
  const { data, error } = await admin
    .from("carrinhos_abandonados")
    .select("id,email,nome,oferta_id,checkout_url,abandonado_em")
    .is("convertido_em", null)
    .gte("abandonado_em", new Date(agora.getTime() - 3 * DIA_MS).toISOString())
    .lte("abandonado_em", new Date(agora.getTime() - 60 * 60 * 1000).toISOString())
    .order("abandonado_em", { ascending: false })
    .limit(50);
  if (error) throw new Error(error.message);
  let enviados = 0;
  const vistos = new Set<string>();
  for (const linha of (data ?? []) as Array<{ id: string; email: string; nome: string | null; oferta_id: string | null; checkout_url: string | null; abandonado_em: string }>) {
    /* Várias tentativas da mesma pessoa: vale a mais recente. */
    if (vistos.has(linha.email)) continue;
    vistos.add(linha.email);
    const abandonadoEm = new Date(linha.abandonado_em);
    if (await comprouDepois(admin, linha.email, abandonadoEm)) {
      await admin.from("carrinhos_abandonados").update({ convertido_em: new Date().toISOString() }).eq("email", linha.email).is("convertido_em", null);
      continue;
    }
    const tipo = lembreteDeCarrinho(abandonadoEm, agora);
    if (!tipo) continue;
    /* Um de cada tipo por pessoa e por dia do abandono. */
    const r = await enviarUmaVez(admin, linha.email, tipo, diaEmBrasilia(abandonadoEm), () => emailDeCarrinho(tipo, linha));
    if (r.enviado) enviados += 1;
  }
  return enviados;
}

/* ------------------------------------------------------------------ */
/* Pix gerado e não pago                                               */
/* ------------------------------------------------------------------ */

export async function enviarLembretesDePix(admin: Admin, agora = new Date()) {
  if (!emailConfigurado()) return 0;
  const { data, error } = await admin
    .from("pagamentos_cakto")
    .select("pedido_id,email,oferta_id,valor,pix_codigo,pix_expira_em,criado_em")
    .eq("produto_id", PRODUTO_KTALOGU)
    .eq("status", "waiting_payment")
    .not("pix_codigo", "is", null)
    .gte("criado_em", new Date(agora.getTime() - 2 * DIA_MS).toISOString())
    .limit(50);
  if (error) throw new Error(error.message);
  let enviados = 0;
  for (const linha of (data ?? []) as Array<{ pedido_id: string; email: string; oferta_id: string | null; valor: number | string | null; pix_codigo: string; pix_expira_em: string | null; criado_em: string | null }>) {
    if (!linha.criado_em) continue;
    const expira = linha.pix_expira_em ? new Date(linha.pix_expira_em) : null;
    if (!lembrarDoPix(new Date(linha.criado_em), expira, agora)) continue;
    const plano = planoDaOferta(linha.oferta_id);
    const r = await enviarUmaVez(admin, linha.email, "pix-pendente", linha.pedido_id, () => ({
      assunto: "Seu Pix da Ktalogu ainda está esperando pagamento",
      ...montarEmail({
        resumo: "Copie o código Pix do e-mail e pague pelo app do seu banco.",
        etiqueta: "Pagamento pendente",
        tom: "atencao",
        titulo: "Seu Pix ainda não foi pago",
        paragrafos: [
          "Geramos o Pix da sua assinatura da Ktalogu, mas o pagamento ainda não apareceu por aqui.",
          "É só copiar o código abaixo e colar na opção Pix copia e cola do app do seu banco. Assim que pagar, o acesso é liberado sozinho.",
        ],
        linhas: [
          ...(plano ? [{ rotulo: "Plano", valor: plano }] : []),
          ...(linha.valor !== null ? [{ rotulo: "Valor", valor: moeda(Number(linha.valor)) }] : []),
          ...(expira ? [{ rotulo: "Pague até", valor: `${dataCurta(expira)} às ${expira.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", timeZone: "America/Sao_Paulo" })}` }] : []),
        ],
        codigo: { rotulo: "Pix copia e cola", valor: linha.pix_codigo },
      }),
    }));
    if (r.enviado) enviados += 1;
  }
  return enviados;
}

/* ------------------------------------------------------------------ */
/* Primeiros passos                                                    */
/* ------------------------------------------------------------------ */

const PASSOS: Record<PrimeiroPasso, { numero: number; assunto: string; titulo: string; paragrafos: string[]; botao: { texto: string; link: string } }> = {
  "passo-produto": {
    numero: 1,
    assunto: "Primeiro passo: cadastre seu primeiro produto",
    titulo: "Cadastre seu primeiro produto",
    paragrafos: [
      "Tudo na Ktalogu começa pelos produtos: é com eles que você monta orçamentos, pedidos e a sua loja virtual.",
      "Comece por um só, o que você mais vende. Nome, foto e preço já bastam. Leva uns 2 minutos.",
    ],
    botao: { texto: "Cadastrar meu primeiro produto", link: `${PAINEL}/dashboard/products/new` },
  },
  "passo-loja": {
    numero: 2,
    assunto: "Segundo passo: deixe sua loja com a sua cara",
    titulo: "Deixe sua loja com a sua cara",
    paragrafos: [
      "Sua loja virtual já está no ar. Falta colocar a sua logo e as suas cores para ela ficar com a cara da sua empresa.",
      "Depois é só mandar o link para os clientes no WhatsApp e no Instagram.",
    ],
    botao: { texto: "Personalizar minha loja", link: `${PAINEL}/dashboard/catalog` },
  },
  "passo-orcamento": {
    numero: 3,
    assunto: "Terceiro passo: mande seu primeiro orçamento",
    titulo: "Mande seu primeiro orçamento",
    paragrafos: [
      "Com os produtos cadastrados, o orçamento sai em segundos: o cliente recebe um link bonito, aprova pelo celular e o pedido já entra na produção.",
      "Faça o primeiro com um cliente de verdade e veja a diferença.",
    ],
    botao: { texto: "Criar meu primeiro orçamento", link: `${PAINEL}/dashboard/quotes/new` },
  },
};

async function donoDaConta(admin: Admin, email: string): Promise<string | null> {
  const { data: empresa } = await admin.from("companies").select("owner_id").eq("billing_email", email).limit(1);
  const pelaEmpresa = (empresa as Array<{ owner_id: string }> | null)?.[0]?.owner_id;
  if (pelaEmpresa) return pelaEmpresa;
  const { data } = await admin.rpc("get_auth_user_id_by_email", { p_email: email });
  return typeof data === "string" && data ? data : null;
}

export async function enviarPrimeirosPassos(admin: Admin, agora = new Date()) {
  if (!emailConfigurado()) return 0;
  /* Quem assinou o plano novo nos últimos 10 dias (a primeira assinatura da conta). */
  const { data, error } = await admin
    .from("assinaturas_cakto")
    .select("email,criada_em")
    .eq("produto_id", PRODUTO_KTALOGU)
    .gte("criada_em", new Date(agora.getTime() - 10 * DIA_MS).toISOString())
    .order("criada_em", { ascending: true })
    .limit(200);
  if (error) throw new Error(error.message);
  const primeiraDe = new Map<string, Date>();
  for (const l of (data ?? []) as Array<{ email: string; criada_em: string }>) if (!primeiraDe.has(l.email)) primeiraDe.set(l.email, new Date(l.criada_em));

  let enviados = 0;
  for (const [email, desde] of primeiraDe) {
    /* Assinatura anterior (renovação antecipada, troca) não é conta nova. */
    const { count: antes } = await admin
      .from("assinaturas_cakto")
      .select("id", { count: "exact", head: true })
      .eq("email", email)
      .lt("criada_em", desde.toISOString());
    if (antes) continue;
    const { data: acesso } = await admin.from("users_app").select("status,expires_at").eq("email", email).maybeSingle();
    const vence = lerVencimento(acesso?.expires_at);
    if (!vence || vence.getTime() <= agora.getTime() || !statusLibera(acesso?.status).libera) continue;

    const dias = Math.floor((agora.getTime() - desde.getTime()) / DIA_MS);
    if (dias < 1 || dias >= 10) continue;
    const dono = await donoDaConta(admin, email);
    if (!dono) continue;
    const [{ count: produtos }, { count: orcamentos }, { data: perfil }] = await Promise.all([
      admin.from("products").select("id", { count: "exact", head: true }).eq("user_id", dono),
      admin.from("quotes").select("id", { count: "exact", head: true }).eq("user_id", dono),
      admin.from("profiles").select("logo_url").eq("id", dono).maybeSingle(),
    ]);
    const passo = primeiroPasso(dias, { produto: Boolean(produtos), orcamento: Boolean(orcamentos), loja: Boolean(perfil?.logo_url) });
    if (!passo) continue;
    const p = PASSOS[passo];
    const r = await enviarUmaVez(admin, email, passo, "conta", () => ({
      assunto: p.assunto,
      ...montarEmail({
        resumo: p.paragrafos[0],
        etiqueta: `Primeiros passos · ${p.numero} de 3`,
        titulo: p.titulo,
        paragrafos: [...p.paragrafos, "Precisa de ajuda? Chame o suporte no WhatsApp: a gente te ajuda a configurar."],
        botao: p.botao,
      }),
    }));
    if (r.enviado) enviados += 1;
  }
  return enviados;
}

/* ------------------------------------------------------------------ */
/* Aviso ao dono da plataforma                                         */
/* ------------------------------------------------------------------ */

function emailsDoDono() {
  return String(process.env.OWNER_ACCESS_EMAILS || "")
    .split(",")
    .map((e) => e.trim().toLowerCase())
    .filter(Boolean);
}

const METODO: Record<string, string> = { credit_card: "Cartão", pix: "Pix", pix_auto: "Pix automático", boleto: "Boleto" };

const FRASE_PARA_O_DONO: Record<string, string> = {
  nova: "Uma nova assinatura dos planos novos entrou e o acesso já foi liberado.",
  troca: "Um cliente trocou de plano ou renovou antes do vencimento. Os dias que ele ainda tinha foram somados e a assinatura anterior foi cancelada na Cakto.",
  renovacao: "Uma assinatura foi renovada e o acesso foi estendido.",
  recusado: "A cobrança da renovação foi recusada. O cliente já foi avisado por e-mail; se não pagar, o acesso fecha no dia seguinte ao vencimento.",
  cancelamento: "Um cliente cancelou a assinatura. Ele usa até o fim do período que já pagou.",
  reembolso: "Um pagamento foi reembolsado e o acesso daquele período foi cortado.",
  chargeback: "Um pagamento foi contestado no cartão (chargeback) e o acesso foi cortado.",
};

/**
 * Cada venda, renovação, troca, recusa, cancelamento, reembolso e chargeback
 * vai para o e-mail do dono (OWNER_ACCESS_EMAILS). Um por pedido e acontecimento.
 */
export async function avisarODono(admin: Admin, aviso: AvisoCakto, detalheDoResultado: string, emailDaConta: string) {
  const acontecimento = acontecimentoParaODono(aviso.evento, detalheDoResultado);
  if (!acontecimento) return;
  const { emoji, titulo, tom } = TITULO_PARA_O_DONO[acontecimento];
  const plano = planoDaOferta(aviso.ofertaId);
  const linhas = [
    { rotulo: "Cliente", valor: aviso.nome || "—" },
    { rotulo: "E-mail da conta", valor: emailDaConta },
    ...(aviso.email && aviso.email !== emailDaConta ? [{ rotulo: "Quem pagou", valor: aviso.email }] : []),
    ...(plano ? [{ rotulo: "Plano", valor: plano }] : []),
    ...(aviso.valor !== null ? [{ rotulo: "Valor", valor: moeda(aviso.valor) }] : []),
    ...(aviso.metodo ? [{ rotulo: "Forma", valor: METODO[aviso.metodo] ?? aviso.metodo }] : []),
    ...(aviso.refId ? [{ rotulo: "Pedido", valor: aviso.refId }] : []),
  ];
  for (const dono of emailsDoDono()) {
    await enviarUmaVez(admin, dono, `dono-${acontecimento}`, aviso.pedidoId ?? aviso.chave, () => ({
      assunto: `${emoji} ${titulo}: ${aviso.nome || emailDaConta}${aviso.valor !== null ? ` · ${moeda(aviso.valor)}` : ""}`,
      ...montarEmail({
        resumo: `${aviso.nome || emailDaConta}${plano ? ` · ${plano}` : ""}`,
        etiqueta: "Assinaturas da Ktalogu",
        tom,
        titulo: `${emoji} ${titulo}`,
        paragrafos: [FRASE_PARA_O_DONO[acontecimento]],
        linhas,
      }),
    })).catch((e) => console.error("[dono] aviso não saiu", acontecimento, e instanceof Error ? e.message : e));
  }
}
