import { ErroDigital, type ContextoDigital } from "../contexto";
import { darAcesso, listarAlunos, mexerNoAluno } from "../alunos";
import { acordarFilaDigital } from "../fila";

/*
 * O que as rotas de "Clientes e acessos" fazem (app/api/digitais/alunos/**),
 * fora delas: a tela do painel e o assistente (MCP) chamam as mesmas funções.
 */

/* Quem tem acesso aos produtos digitais da loja (e os produtos, para dar acesso). */
export async function listarAcessosDaLoja({ admin, lojaId, pode }: ContextoDigital) {
  const [alunos, produtos] = await Promise.all([
    listarAlunos(admin, lojaId),
    admin.from("products").select("id,name").eq("user_id", lojaId).eq("product_kind", "digital").order("name", { ascending: true }).limit(500),
  ]);
  return {
    podeEditar: pode("digital.students.write"),
    alunos,
    produtos: ((produtos.data ?? []) as Array<{ id: string; name: string }>).map((p) => ({ id: p.id, nome: p.name })),
  };
}

function prazoDoCorpo(valor: unknown): number | null {
  if (valor === null || valor === undefined || valor === "") return null;
  const numero = Number(valor);
  if (!Number.isFinite(numero) || numero < 1) throw new ErroDigital("Confira o prazo em dias.", 400);
  return Math.min(3650, Math.round(numero));
}

/* Dar acesso de cortesia (e avisar por e-mail, se a loja quiser). */
export async function darAcessoDeCortesia({ admin, lojaId, user }: ContextoDigital, bruto: unknown) {
  const corpo = bruto as Record<string, unknown> | null;
  const produtoId = typeof corpo?.produtoId === "string" ? corpo.produtoId : "";
  if (!/^[0-9a-f-]{36}$/i.test(produtoId)) throw new ErroDigital("Escolha o produto.", 400);
  const cliente =
    typeof corpo?.clienteId === "string" && /^[0-9a-f-]{36}$/i.test(corpo.clienteId)
      ? { id: corpo.clienteId }
      : { nome: String(corpo?.nome ?? ""), email: String(corpo?.email ?? "") };
  const resultado = await darAcesso(admin, { lojaId, quem: user.id, cliente, produtoId, prazoDias: prazoDoCorpo(corpo?.prazoDias) });

  let avisado = false;
  if (corpo?.avisar === true && resultado.email) {
    /* Um aviso por minuto no máximo: o clique duplo não manda dois e-mails. */
    const minuto = new Date().toISOString().slice(0, 16);
    const { error } = await admin.from("digital_outbox").upsert(
      {
        user_id: lojaId,
        canal: "email",
        tipo: "entrega",
        destino: resultado.email,
        dados: { cortesia: true, client_id: resultado.clienteId, product_id: produtoId },
        chave_unica: `cortesia:${resultado.clienteId}:${produtoId}:${minuto}`,
      },
      { onConflict: "chave_unica", ignoreDuplicates: true }
    );
    avisado = !error;
    if (avisado) acordarFilaDigital();
  }
  return { ok: true, ...resultado, avisado, semEmail: corpo?.avisar === true && !resultado.email };
}

/* Bloquear, reativar ou mudar o prazo de uma pessoa num produto. */
export async function mexerNoAcesso({ admin, lojaId }: ContextoDigital, bruto: unknown) {
  const corpo = bruto as Record<string, unknown> | null;
  const clienteId = typeof corpo?.clienteId === "string" ? corpo.clienteId : "";
  const produtoId = typeof corpo?.produtoId === "string" ? corpo.produtoId : "";
  const acao = corpo?.acao;
  if (!/^[0-9a-f-]{36}$/i.test(clienteId) || !/^[0-9a-f-]{36}$/i.test(produtoId)) throw new ErroDigital("Acesso inválido.", 400);
  if (acao !== "bloquear" && acao !== "reativar" && acao !== "prazo") throw new ErroDigital("Ação inválida.", 400);
  return mexerNoAluno(admin, { lojaId, clienteId, produtoId, acao, prazoDias: acao === "prazo" ? prazoDoCorpo(corpo?.prazoDias) : undefined });
}

/* Procura um cliente da loja para dar acesso (nome, e-mail ou documento). */
export async function buscarClienteParaAcesso({ admin, lojaId }: ContextoDigital, termo: string) {
  const busca = String(termo || "")
    .replace(/[%_\,()]/g, " ")
    .trim()
    .slice(0, 80);
  if (busca.length < 2) return { clientes: [] };
  const digitos = busca.replace(/\D/g, "");
  const filtros = [`name.ilike.%${busca}%`, `email.ilike.%${busca}%`];
  if (digitos.length >= 3) filtros.push(`document.ilike.%${digitos}%`);
  const { data } = await admin
    .from("clients")
    .select("id,name,email")
    .eq("user_id", lojaId)
    .eq("is_deleted", false)
    .eq("is_system_placeholder", false)
    .or(filtros.join(","))
    .order("name", { ascending: true })
    .limit(8);
  return {
    clientes: ((data ?? []) as Array<{ id: string; name: string | null; email: string | null }>).map((c) => ({
      id: c.id,
      nome: c.name || "Cliente",
      email: c.email || null,
    })),
  };
}
