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

import { novoCodigoDoCertificado } from "../certificado";
import { cargaHorariaEmMinutos } from "../curso";
import { lerConfigDigitalDaLoja } from "../produto";
import { estruturaParaAluno, progressoDoAluno } from "./curso";
import { lerAjustesDigitais } from "./vitrine";

/*
 * Os certificados do lado da loja. Nasce um por aluno e curso, quando a
 * última aula fica concluída (com o certificado ligado nas Configurações e no
 * curso). O que vale no papel fica guardado como foi emitido: mudar o nome do
 * curso depois não muda o certificado.
 */

export type CertificadoDoAluno = {
  id: string;
  codigo: string;
  produtoId: string;
  curso: string;
  cargaHorariaMin: number;
  emitidoEm: string;
};

export type CertificadoPublico = CertificadoDoAluno & {
  clienteId: string;
  aluno: string;
  assinatura: string | null;
  revogadoEm: string | null;
};

type LinhaDoCertificado = {
  id: string;
  codigo: string;
  client_id: string;
  product_id: string;
  nome_do_aluno: string;
  curso: string;
  carga_horaria_min: number;
  assinatura: string | null;
  emitido_em: string;
  revogado_em: string | null;
};

const COLUNAS = "id,codigo,client_id,product_id,nome_do_aluno,curso,carga_horaria_min,assinatura,emitido_em,revogado_em";

function paraATela(linha: LinhaDoCertificado): CertificadoPublico {
  return {
    id: linha.id,
    codigo: linha.codigo,
    produtoId: linha.product_id,
    curso: linha.curso,
    cargaHorariaMin: linha.carga_horaria_min,
    emitidoEm: linha.emitido_em,
    clienteId: linha.client_id,
    aluno: linha.nome_do_aluno,
    assinatura: linha.assinatura,
    revogadoEm: linha.revogado_em,
  };
}

/** O certificado pelo código (para a página pública e o PDF). */
export async function lerCertificado(admin: SupabaseClient, lojaId: string, codigo: string): Promise<CertificadoPublico | null> {
  const { data } = await admin.from("digital_certificates").select(COLUNAS).eq("user_id", lojaId).eq("codigo", codigo).maybeSingle();
  return data ? paraATela(data as LinhaDoCertificado) : null;
}

/** Os certificados válidos do aluno nesta loja (área de membros). */
export async function certificadosDoAluno(admin: SupabaseClient, lojaId: string, clienteId: string): Promise<CertificadoDoAluno[]> {
  const { data } = await admin
    .from("digital_certificates")
    .select(COLUNAS)
    .eq("user_id", lojaId)
    .eq("client_id", clienteId)
    .is("revogado_em", null)
    .order("emitido_em", { ascending: false })
    .limit(100);
  return ((data ?? []) as LinhaDoCertificado[]).map(paraATela);
}

/* O ano de hoje no calendário de Brasília. */
function anoEmBrasilia(): number {
  return Number(new Date().toLocaleDateString("en-CA", { timeZone: "America/Sao_Paulo" }).slice(0, 4)) || new Date().getUTCFullYear();
}

/**
 * Emite o certificado se o aluno concluiu todas as aulas do curso (e ele está
 * ligado). Devolve o que já existia, se havia. O e-mail "seu certificado está
 * pronto" vai para a fila do painel.
 */
export async function emitirCertificadoSeConcluiu(
  admin: SupabaseClient,
  params: { lojaId: string; clienteId: string; produtoId: string; inicio: string | null }
): Promise<{ codigo: string; novo: boolean } | null> {
  const { lojaId, clienteId, produtoId } = params;
  const jaTem = async () => {
    const { data } = await admin
      .from("digital_certificates")
      .select("codigo,revogado_em")
      .eq("user_id", lojaId)
      .eq("client_id", clienteId)
      .eq("product_id", produtoId)
      .maybeSingle();
    const linha = data as { codigo: string; revogado_em: string | null } | null;
    return linha ? (linha.revogado_em ? { codigo: "", novo: false, revogado: true } : { codigo: linha.codigo, novo: false, revogado: false }) : null;
  };
  const existente = await jaTem();
  if (existente) return existente.revogado ? null : { codigo: existente.codigo, novo: false };

  const [produto, ajustes] = await Promise.all([
    admin.from("products").select("name,digital_config").eq("id", produtoId).eq("user_id", lojaId).maybeSingle(),
    lerAjustesDigitais(admin, lojaId),
  ]);
  const linhaDoProduto = produto.data as { name: string; digital_config: unknown } | null;
  if (!linhaDoProduto) return null;
  const config = lerConfigDigitalDaLoja(linhaDoProduto.digital_config);
  if (config.tipo !== "curso" || !config.curso || !ajustes.certificado.emitir || !config.curso.certificado.emitir) return null;

  /* Todas as aulas que o aluno vê, concluídas (a que ainda não abriu também conta: falta). */
  const [modulos, progresso] = await Promise.all([
    estruturaParaAluno(admin, { lojaId, produtoId, inicio: params.inicio, equipe: false }),
    progressoDoAluno(admin, clienteId, produtoId),
  ]);
  const aulas = modulos.flatMap((m) => m.aulas);
  if (!aulas.length || aulas.some((a) => !progresso.get(a.id)?.concluida)) return null;
  const duracaoDosVideos = aulas.reduce((soma, a) => soma + (a.tipo === "video" ? Number(a.duracaoS) || 0 : 0), 0);

  const [cliente, perfil] = await Promise.all([
    admin.from("clients").select("name,email").eq("id", clienteId).eq("user_id", lojaId).maybeSingle(),
    admin.from("profiles").select("catalog_name,store_name").eq("id", lojaId).maybeSingle(),
  ]);
  const linhaDoCliente = cliente.data as { name: string | null; email: string | null } | null;
  if (!linhaDoCliente) return null;
  const linhaDoPerfil = perfil.data as { catalog_name?: string | null; store_name?: string | null } | null;
  const nomeDaLoja = String(linhaDoPerfil?.catalog_name || linhaDoPerfil?.store_name || "Loja");

  for (let tentativa = 0; tentativa < 4; tentativa += 1) {
    const { data, error } = await admin
      .from("digital_certificates")
      .insert({
        user_id: lojaId,
        client_id: clienteId,
        product_id: produtoId,
        codigo: novoCodigoDoCertificado(nomeDaLoja, anoEmBrasilia()),
        nome_do_aluno: String(linhaDoCliente.name || "").replace(/\s+/g, " ").trim().slice(0, 160) || "Cliente",
        curso: linhaDoProduto.name.trim().slice(0, 200) || "Conteúdo",
        carga_horaria_min: Math.min(100000, cargaHorariaEmMinutos(config.curso.certificado, duracaoDosVideos)),
        assinatura: ajustes.certificado.assinatura,
      })
      .select("id,codigo")
      .single();
    if (!error && data) {
      const novo = data as { id: string; codigo: string };
      const email = String(linhaDoCliente.email || "").trim().toLowerCase();
      if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) && email.length <= 320) {
        await admin.from("digital_outbox").insert({
          user_id: lojaId,
          canal: "email",
          tipo: "certificado",
          destino: email,
          dados: { certificado_id: novo.id, client_id: clienteId, product_id: produtoId },
          chave_unica: `certificado:${novo.id}`,
        });
      }
      return { codigo: novo.codigo, novo: true };
    }
    /* Outro pedido emitiu junto (um por aluno e curso), ou o código sorteado repetiu. */
    if (error?.code === "23505") {
      const outro = await jaTem();
      if (outro) return outro.revogado ? null : { codigo: outro.codigo, novo: false };
      continue;
    }
    console.error("[digitais] certificado", error?.message);
    return null;
  }
  return null;
}

/** O endereço público do certificado: no domínio próprio da loja, quando há. */
export async function enderecoDoCertificado(admin: SupabaseClient, params: { lojaId: string; slug: string; codigo: string }): Promise<string> {
  const { data } = await admin.from("profile_custom_domains").select("domain").eq("profile_id", params.lojaId).eq("verified", true).limit(1);
  const dominio = String(((data ?? []) as Array<{ domain?: string | null }>)[0]?.domain || "").trim().toLowerCase();
  const codigo = encodeURIComponent(params.codigo);
  if (dominio && /^[a-z0-9.-]+$/.test(dominio)) return `https://${dominio}/certificado/${codigo}`;
  const base = String(process.env.NEXT_PUBLIC_PUBLIC_CATALOG_BASE_URL || (process.env.NODE_ENV === "production" ? "https://ktalogu.com.br" : "http://localhost:3001"))
    .trim()
    .replace(/\/+$/, "");
  return `${base}/${encodeURIComponent(params.slug)}/certificado/${codigo}`;
}
