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

import { formatDocument } from "@/lib/document-utils";

import type { DadosDaCompra, RespostaDaCompra } from "../compra";
import { TEXTO_DO_ACEITE } from "../textos";

/*
 * O lado do servidor da compra rápida: o produto que está à venda, o cliente
 * (achado ou criado) e o pedido da loja, gravado pela mesma função do banco
 * de sempre (`create_public_catalog_order`).
 */

export type ProdutoAVenda = {
  id: string;
  user_id: string;
  name: string;
  price: number;
  image_url: string | null;
  digital_config: unknown;
  /* As perguntas da compra sob encomenda. */
  custom_fields_config: unknown;
};

export async function lerProdutoDigitalAVenda(admin: SupabaseClient, lojaId: string, produtoId: string): Promise<ProdutoAVenda | null> {
  if (!/^[0-9a-f-]{36}$/i.test(produtoId)) return null;
  const { data } = await admin
    .from("products")
    .select("id,user_id,name,price,image_url,digital_config,custom_fields_config")
    .eq("id", produtoId)
    .eq("user_id", lojaId)
    .eq("product_kind", "digital")
    .eq("active", true)
    .eq("show_in_catalog", true)
    .maybeSingle();
  if (!data) return null;
  const linha = data as ProdutoAVenda;
  return { ...linha, price: Math.max(0, Math.round(Number(linha.price || 0) * 100) / 100) };
}

/**
 * Códigos e licenças: quantos ainda podem ser vendidos (os livres menos as
 * unidades que já esperam um, e as da pré-venda, que levam o seu no dia do
 * lançamento). Se a conta falhar, não trava a venda: a unidade espera e o
 * código sai sozinho quando a loja adicionar mais.
 */
export async function codigosAVenda(admin: SupabaseClient, lojaId: string, produtoId: string): Promise<number> {
  const [livres, esperando] = await Promise.all([
    admin
      .from("digital_codes")
      .select("id", { count: "exact", head: true })
      .eq("user_id", lojaId)
      .eq("product_id", produtoId)
      .is("entitlement_id", null)
      .is("apagado_em", null),
    /* Só a unidade do código conta (o produto pode levar um arquivo junto, que também nasce agendado). */
    admin
      .from("digital_entitlements")
      .select("id,digital_deliverables!digital_entitlements_deliverable_id_fkey!inner(tipo)", { count: "exact", head: true })
      .eq("user_id", lojaId)
      .eq("product_id", produtoId)
      .in("status", ["aguardando_codigo", "agendado"])
      .eq("digital_deliverables.tipo", "codigos"),
  ]);
  if (livres.error || esperando.error) return 1;
  return (livres.count ?? 0) - (esperando.count ?? 0);
}

/*
 * O cliente da compra.
 *
 * Quem está logado no portal compra como ele mesmo. Senão, o CPF (ou o
 * e-mail) já cadastrado nesta loja põe a compra no cadastro que existe, SEM
 * mudar nada nele: quem digita um CPF não ganha o direito de trocar o e-mail
 * de outra pessoa. A entrega vai para o e-mail digitado (guardado no pedido).
 * Sem cadastro, nasce um cliente novo. No produto grátis não há CPF: vale o
 * e-mail.
 */
export async function acharOuCriarCliente(
  admin: SupabaseClient,
  lojaId: string,
  dados: DadosDaCompra,
  clienteLogadoId: string | null
): Promise<{ id: string; novo: boolean }> {
  if (clienteLogadoId) return { id: clienteLogadoId, novo: false };

  const formatado = dados.documento ? formatDocument(dados.documento) : "";
  for (const documento of Array.from(new Set([dados.documento, formatado])).filter(Boolean)) {
    const { data } = await admin
      .from("clients")
      .select("id")
      .eq("user_id", lojaId)
      .eq("document", documento)
      .eq("is_deleted", false)
      .eq("is_system_placeholder", false)
      .limit(1);
    const achado = (data as Array<{ id: string }> | null)?.[0];
    if (achado) return { id: achado.id, novo: false };
  }

  const { data: porEmail } = await admin
    .from("clients")
    .select("id")
    .eq("user_id", lojaId)
    .ilike("email", dados.email)
    .eq("is_deleted", false)
    .eq("is_system_placeholder", false)
    .limit(1);
  const achadoPorEmail = (porEmail as Array<{ id: string }> | null)?.[0];
  if (achadoPorEmail) return { id: achadoPorEmail.id, novo: false };

  const { data: criado, error } = await admin
    .from("clients")
    .insert({
      user_id: lojaId,
      name: dados.nome,
      email: dados.email,
      whatsapp: dados.whatsapp || null,
      phone: dados.whatsapp || null,
      document: dados.documento || null,
      type: dados.documento.length === 14 ? "pj" : "pf",
      origin: "loja_digital",
    })
    .select("id")
    .single();
  if (error || !criado) throw new Error("Não foi possível registrar seus dados. Tente de novo.");
  return { id: (criado as { id: string }).id, novo: true };
}

/* O pedido da loja da compra digital: um item, preço do banco. */
export async function gravarPedidoDigital(
  admin: SupabaseClient,
  params: {
    slug: string;
    produto: ProdutoAVenda;
    clienteId: string;
    dados: DadosDaCompra;
    provedor: string | null;
    /* Sob encomenda: o que o comprador respondeu (vai no item do pedido). */
    respostas?: RespostaDaCompra[];
  }
): Promise<{ id: string; number: number | null }> {
  const { slug, produto, clienteId, dados, provedor } = params;
  const respostas = params.respostas ?? [];
  /* "Nome no convite: Ana / Idade: 5": aparece no pedido, como no carrinho. */
  const textoDasRespostas = respostas.map((r) => `${r.title}: ${r.value}`).join(" / ");
  const total = produto.price;
  const payload = {
    currency: "BRL",
    subtotal: total,
    discount: 0,
    total,
    customer_name: dados.nome,
    customer_phone: dados.whatsapp,
    customer_whatsapp: dados.whatsapp,
    notes: "",
    whatsapp_url: "",
    items: [
      {
        product_id: produto.id,
        name: produto.name,
        description: textoDasRespostas,
        quantity: 1,
        unit_type: "unit",
        width_m: 0,
        height_m: 0,
        length_m: 0,
        unit_price: total,
        total_price: total,
        variation_description: textoDasRespostas,
        selected_options: respostas.length ? { options: [], custom_fields: respostas } : null,
        raw_price_on_request: false,
      },
    ],
    cart_payload: {
      source: "compra_digital",
      /* Marca lida pela conferência do pagamento: compra digital sempre vira
         pedido interno quando aprovada (é o pedido pago que libera a entrega). */
      compra_digital: true,
      client_email: dados.email,
      client_document: dados.documento,
      email_da_entrega: dados.email,
      /* O comprador marcou que o acesso começa logo depois do pagamento
         (direito de arrependimento do conteúdo digital): fica a hora e o texto.
         No grátis não há pagamento nem o que confirmar. */
      ...(total > 0 ? { aceite_em: new Date().toISOString(), aceite_texto: TEXTO_DO_ACEITE } : {}),
      client_profile: {
        name: dados.nome,
        email: dados.email,
        phone: dados.whatsapp,
        whatsapp: dados.whatsapp,
        document: dados.documento,
      },
    },
  };

  const resultado = await admin.rpc("create_public_catalog_order", { p_slug: slug, p_payload: payload });
  const id = (resultado.data as { id?: string } | null)?.id;
  if (resultado.error || !id) throw new Error("Não foi possível registrar a compra.");

  await admin
    .from("catalog_orders")
    .update({
      kind: "order",
      client_id: clienteId,
      payment_provider: provedor,
      payment_required: total > 0,
      payment_status: "unpaid",
      updated_at: new Date().toISOString(),
    })
    .eq("id", id);

  return { id: String(id), number: (resultado.data as { number?: number } | null)?.number ?? null };
}

/**
 * Produto grátis: a resposta da caixa "novidades" (desmarcada por padrão),
 * com o texto que a pessoa viu e a hora. Guarda também o "não". Falhar aqui
 * não desfaz a compra.
 */
export async function registrarNovidades(
  admin: SupabaseClient,
  params: { lojaId: string; clienteId: string; produtoId: string; catalogOrderId: string; novidades: boolean; texto: string; ip: string | null }
): Promise<void> {
  const { error } = await admin.from("digital_consents").insert({
    user_id: params.lojaId,
    client_id: params.clienteId,
    product_id: params.produtoId,
    catalog_order_id: params.catalogOrderId,
    novidades: params.novidades,
    texto: params.texto.slice(0, 500),
    ip: params.ip?.slice(0, 64) ?? null,
  });
  if (error) console.error("[digitais] novidades do grátis", error.message);
}
