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

import { lerVencimento, statusLibera } from "@/lib/assinatura";
import { avisosDoDia, type TipoDeAviso } from "@/lib/avisos-da-assinatura";
import { emailConfigurado, enviarEmail, montarEmail } from "@/lib/email-transacional";

/**
 * Os avisos da assinatura mandados por e-mail. Cada (e-mail, tipo, referência)
 * sai uma vez só: a linha em `avisos_da_assinatura` é gravada antes do envio
 * e apagada se o envio falhar, para a próxima volta tentar de novo.
 */

type Admin = SupabaseClient;

const PAINEL = "https://admin.ktalogu.com.br/dashboard/assinatura";

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

export function textoDoAviso(tipo: TipoDeAviso, referencia: string) {
  const quando = /^\d{4}-\d{2}-\d{2}$/.test(referencia) ? dataCurta(referencia) : "";
  switch (tipo) {
    case "vence-em-7":
    case "vence-em-3":
    case "vence-em-1": {
      const falta = tipo === "vence-em-7" ? "7 dias" : tipo === "vence-em-3" ? "3 dias" : "1 dia";
      return {
        assunto: `Sua assinatura da Ktalogu vence em ${falta}`,
        ...montarEmail({
          resumo: `O acesso vale até ${quando}. Renovando agora, os dias que faltam são somados.`,
          etiqueta: "Renovação",
          tom: "atencao",
          titulo: `Sua assinatura vence em ${falta}`,
          paragrafos: [
            "Para a sua equipe continuar usando a Ktalogu sem interrupção, renove antes do vencimento.",
            "Renovando agora, você não perde nada: os dias que ainda faltam são somados ao novo período.",
          ],
          linhas: [
            { rotulo: "Vence em", valor: quando },
            { rotulo: "Depois dessa data", valor: "Painel fechado até renovar" },
          ],
          botao: { texto: "Renovar minha assinatura", link: PAINEL },
        }),
      };
    }
    case "acesso-encerrado":
      return {
        assunto: "Seu acesso à Ktalogu foi pausado",
        ...montarEmail({
          resumo: "Seus dados continuam guardados. Renove e tudo volta como estava.",
          etiqueta: "Acesso pausado",
          tom: "ruim",
          titulo: "Seu acesso à Ktalogu foi pausado",
          paragrafos: [
            "A assinatura da sua empresa venceu e o painel ficou fechado.",
            "Fique tranquilo: produtos, pedidos, clientes e a loja continuam guardados. Assim que o pagamento for confirmado, tudo volta exatamente como estava.",
          ],
          linhas: [
            { rotulo: "Venceu em", valor: quando },
            { rotulo: "Seus dados", valor: "Guardados" },
          ],
          botao: { texto: "Reativar minha assinatura", link: PAINEL },
        }),
      };
    case "pagamento-confirmado":
      return {
        assunto: "Pagamento confirmado: sua assinatura da Ktalogu está ativa",
        ...montarEmail({
          resumo: quando ? `Sua assinatura está ativa até ${quando}.` : "Sua assinatura está ativa.",
          etiqueta: "Pagamento confirmado",
          tom: "bom",
          titulo: "Tudo certo com a sua assinatura",
          paragrafos: [
            "Recebemos o seu pagamento e a sua empresa já pode usar a Ktalogu normalmente.",
            "Obrigado por confiar na gente. O histórico de pagamentos fica sempre disponível em Assinatura, no painel.",
          ],
          linhas: [
            { rotulo: "Situação", valor: "Ativa" },
            ...(quando ? [{ rotulo: "Válida até", valor: quando }] : []),
          ],
          botao: { texto: "Abrir o painel", link: "https://admin.ktalogu.com.br/dashboard" },
        }),
      };
    case "pagamento-recusado":
      return {
        assunto: "Não conseguimos cobrar a renovação da sua assinatura",
        ...montarEmail({
          resumo: "Confira o cartão ou renove pelo painel para não perder o acesso.",
          etiqueta: "Ação necessária",
          tom: "ruim",
          titulo: "A cobrança da renovação não passou",
          paragrafos: [
            "Tentamos cobrar a renovação da sua assinatura e o pagamento foi recusado. Isso costuma acontecer com cartão vencido, sem limite ou bloqueado.",
            "Confira o cartão usado na assinatura ou renove pelo painel. Se o pagamento não entrar, o acesso fecha no dia seguinte ao vencimento.",
          ],
          linhas: [
            { rotulo: "Situação", valor: "Pagamento recusado" },
            { rotulo: "O que fazer", valor: "Conferir o cartão ou renovar" },
          ],
          botao: { texto: "Resolver agora", link: PAINEL },
        }),
      };
    case "boas-vindas":
      /* Sai por `enviarBoasVindas`, que tem o link de criar a senha. */
      return { assunto: "Bem-vindo à Ktalogu", ...montarEmail({ resumo: "", etiqueta: "Boas-vindas", titulo: "Bem-vindo à Ktalogu", paragrafos: [] }) };
    case "acesso-cortado":
      return {
        assunto: "Sua assinatura da Ktalogu foi encerrada",
        ...montarEmail({
          resumo: "O pagamento foi reembolsado ou contestado. Seus dados continuam guardados.",
          etiqueta: "Assinatura encerrada",
          tom: "ruim",
          titulo: "Sua assinatura foi encerrada",
          paragrafos: [
            "O pagamento da sua assinatura foi reembolsado ou contestado, e o acesso ao painel foi encerrado.",
            "Seus dados continuam guardados. Se quiser voltar, é só assinar de novo pelo painel.",
          ],
          linhas: [
            { rotulo: "Situação", valor: "Encerrada" },
            { rotulo: "Seus dados", valor: "Guardados" },
          ],
          botao: { texto: "Ver os planos", link: PAINEL },
        }),
      };
  }
}

/**
 * O primeiro e-mail de quem acabou de comprar e ainda não tinha login: um só,
 * no desenho da Ktalogu, com o plano, a validade e o botão para criar a senha.
 * Substitui o "redefinir senha" padrão do Supabase (sem a nossa cara, e com o
 * envio de fábrica limitado a poucos por hora). Devolve false quando o e-mail
 * não está configurado ou falhou, para quem chamou cair no e-mail do Supabase.
 */
export async function enviarBoasVindas(
  admin: Admin,
  email: string,
  dados: { plano: "mensal" | "anual"; venceEm: Date; redirectTo: string }
): Promise<boolean> {
  if (!emailConfigurado()) return false;
  const { data: reservado, error } = await admin
    .from("avisos_da_assinatura")
    .insert({ email, tipo: "boas-vindas", referencia: "conta", canal: "email" })
    .select("id")
    .maybeSingle();
  if (error) {
    if (error.code === "23505") return true;
    throw new Error(error.message);
  }
  const desfazer = () => admin.from("avisos_da_assinatura").delete().eq("id", reservado?.id);

  /* O mesmo link do "esqueci minha senha": abre a tela de criar a senha já logado. */
  const { data: link, error: erroDoLink } = await admin.auth.admin.generateLink({
    type: "recovery",
    email,
    options: { redirectTo: dados.redirectTo },
  });
  const endereco = link?.properties?.action_link;
  if (erroDoLink || !endereco) {
    await desfazer();
    return false;
  }

  const vence = dataCurta(new Date(dados.venceEm.getTime() - 3 * 60 * 60 * 1000).toISOString().slice(0, 10));
  const { html, texto } = montarEmail({
    resumo: "Sua assinatura está ativa. Crie sua senha e comece a usar.",
    etiqueta: "Boas-vindas",
    tom: "bom",
    titulo: "Bem-vindo à Ktalogu!",
    paragrafos: [
      "Seu pagamento foi confirmado e a sua conta já está pronta. Falta um passo: criar a sua senha de acesso.",
      "Depois é só entrar no painel e começar a cadastrar produtos, montar a loja e mandar orçamentos. A equipe inteira pode usar, sem pagar por usuário.",
      "Por segurança, o botão abaixo vale por pouco tempo. Se ele vencer, entre em admin.ktalogu.com.br e clique em \"Esqueci minha senha\" com este e-mail.",
    ],
    linhas: [
      { rotulo: "Plano", valor: dados.plano === "anual" ? "Anual" : "Mensal" },
      { rotulo: "Válido até", valor: vence },
      { rotulo: "Seu e-mail de acesso", valor: email },
    ],
    botao: { texto: "Criar minha senha", link: endereco },
  });
  const envio = await enviarEmail(email, "Bem-vindo à Ktalogu: crie sua senha", html, texto);
  if (!envio.ok) {
    await desfazer();
    return false;
  }
  return true;
}

/**
 * Manda um e-mail uma vez só por (e-mail, tipo, referência). A linha em
 * `avisos_da_assinatura` é reservada antes do envio e apagada se ele falhar,
 * para a próxima volta tentar de novo. Sem e-mail configurado, não faz nada.
 */
export async function enviarUmaVez(
  admin: Admin,
  email: string,
  tipo: string,
  referencia: string,
  montar: () => { assunto: string; html: string; texto: string }
) {
  if (!emailConfigurado()) return { enviado: false, motivo: "sem-email" as const };
  const { data: reservado, error } = await admin
    .from("avisos_da_assinatura")
    .insert({ email, tipo, referencia, canal: "email" })
    .select("id")
    .maybeSingle();
  if (error) {
    if (error.code === "23505") return { enviado: false, motivo: "ja-enviado" as const };
    throw new Error(error.message);
  }
  const { assunto, html, texto } = montar();
  const envio = await enviarEmail(email, assunto, html, texto);
  if (!envio.ok) {
    await admin.from("avisos_da_assinatura").delete().eq("id", reservado?.id);
    throw new Error(envio.erro);
  }
  return { enviado: true as const };
}

/** Manda um aviso da assinatura uma vez só. */
export function avisar(admin: Admin, email: string, tipo: TipoDeAviso, referencia: string) {
  return enviarUmaVez(admin, email, tipo, referencia, () => textoDoAviso(tipo, referencia));
}

/** Aviso disparado por um acontecimento (pagamento, recusa, corte). Nunca derruba quem chamou. */
export function avisarSemEsperar(admin: Admin, email: string, tipo: TipoDeAviso, referencia: string) {
  void avisar(admin, email, tipo, referencia).catch((e) =>
    console.error("[avisos] não foi possível avisar", tipo, email, e instanceof Error ? e.message : e)
  );
}

/**
 * Os avisos que dependem da data: vencimento chegando e acesso encerrado.
 * Lê as contas que vencem entre anteontem e daqui a 8 dias.
 */
export async function enviarAvisosDoDia(admin: Admin) {
  if (!emailConfigurado()) return { enviados: 0 };
  const agora = Date.now();
  const de = new Date(agora - 3 * 24 * 60 * 60 * 1000).toISOString();
  const ate = new Date(agora + 8 * 24 * 60 * 60 * 1000).toISOString();
  const { data: contas, error } = await admin
    .from("users_app")
    .select("email,status,expires_at")
    .gte("expires_at", de)
    .lte("expires_at", ate)
    .limit(500);
  if (error) throw new Error(error.message);
  const emails = ((contas ?? []) as Array<{ email: string }>).map((c) => c.email);
  const { data: assinaturas } = emails.length
    ? await admin.from("assinaturas_cakto").select("email,situacao,metodo").in("email", emails)
    : { data: [] };
  const linhas = (assinaturas ?? []) as Array<{ email: string; situacao: string; metodo: string | null }>;
  /* Só avisa quem está no sistema novo. Cliente do plano antigo que ainda
     renova sozinho pelo webhook antigo receberia "vence em" à toa; ele entra
     aqui quando a renovação antiga é cancelada (a linha nasce nessa hora). */
  const conhecidas = new Set(linhas.map((a) => a.email));
  const renovamSozinhas = new Set(
    linhas.filter((a) => a.situacao === "ativa" && (a.metodo === "credit_card" || a.metodo === "pix_auto")).map((a) => a.email)
  );

  let enviados = 0;
  for (const conta of (contas ?? []) as Array<{ email: string; status: string | null; expires_at: string | null }>) {
    if (!conhecidas.has(conta.email)) continue;
    const venceEm = lerVencimento(conta.expires_at);
    const ativa = Boolean(venceEm && venceEm.getTime() > agora && statusLibera(conta.status).libera);
    for (const aviso of avisosDoDia({ email: conta.email, venceEm, ativa, renovaSozinha: renovamSozinhas.has(conta.email) })) {
      try {
        const r = await avisar(admin, conta.email, aviso.tipo, aviso.referencia);
        if (r.enviado) enviados += 1;
      } catch (e) {
        console.error("[avisos] falhou", aviso.tipo, conta.email, e instanceof Error ? e.message : e);
      }
    }
  }
  return { enviados };
}
