import { NextResponse } from "next/server";
import { createAdminClient } from "@/lib/supabase-admin";
import { lerClienteLogado, navegadorDaEquipe } from "@/lib/loja/visao.server";
import { resolverVisao } from "@/lib/loja/regras-da-loja";
import { origemDaRequisicao, tentativaPermitida } from "@/lib/limite-de-tentativas";
import { conferirPrecosNoServidor, normalizarItens, normalizeText } from "@/lib/pedido-da-loja.server";
import { calcularCuponsDoPedido, codigosDoCorpo, cuponsAVista, nomesDoAlcance } from "@/lib/cupom-da-loja.server";
import { fraseDoCupom, rotuloDoBeneficio } from "@/lib/regras-do-cupom";

/*
  A prévia do cupom no carrinho.

  O carrinho manda os itens, o código digitado (se houver) e o frete que está
  na tela; o servidor confere os preços no banco e devolve qual cupom fica
  (o digitado ou o automático que der mais), quanto ele dá, o aviso quando o
  digitado não ficou e os cupons que a loja deixou à vista. Nada é gravado:
  quem fecha o pedido (checkout e /api/catalog/pedido) confere tudo de novo e
  reserva o uso com a trava do banco.
*/

export const dynamic = "force-dynamic";

const COLUNAS_DA_LOJA =
  "id,slug,catalog_price_mode,catalog_price_hidden_text,catalog_price_login_text,catalog_price_notice,catalog_purchase_mode," +
  "catalog_cta_label,catalog_checkout_label,catalog_quote_open_whatsapp,catalog_access_mode,catalog_signup_mode," +
  "catalog_require_login_to_order,catalog_min_order_total,catalog_min_order_items,catalog_status,catalog_status_message,whatsapp_templates";

type Corpo = {
  slug?: string;
  items?: unknown;
  couponCode?: string | null;
  couponCodes?: string[] | null;
  shipping?: { price?: number; destination_zip?: string; pickup?: boolean } | null;
};

const VAZIO = { ok: true, aplicados: [] as unknown[], aplicado: null, avisos: [] as string[], aviso: null, erros: [] as unknown[], erro: null, digitados: [] as unknown[], disponiveis: [] as unknown[] };

export async function POST(request: Request) {
  try {
    if (!tentativaPermitida(`cupom:${origemDaRequisicao(request)}`, 90, 10 * 60)) {
      return NextResponse.json({ ...VAZIO, ok: false, erro: "Muitas tentativas seguidas. Aguarde alguns minutos." }, { status: 429 });
    }
    const body = ((await request.json().catch(() => null)) || {}) as Corpo;
    const slug = normalizeText(body.slug).toLowerCase();
    if (!slug) return NextResponse.json({ ...VAZIO, ok: false, erro: "Loja inválida." }, { status: 400 });

    const admin = createAdminClient();
    const { data: perfil } = await admin.from("profiles").select(COLUNAS_DA_LOJA).eq("slug", slug).maybeSingle();
    const loja = perfil as (Record<string, unknown> & { id: string }) | null;
    if (!loja?.id) return NextResponse.json({ ...VAZIO, ok: false, erro: "Loja não encontrada." }, { status: 404 });

    const [cliente, equipe] = await Promise.all([lerClienteLogado(slug), navegadorDaEquipe(loja.id)]);
    const visao = resolverVisao(loja, cliente ? { id: cliente.id, name: cliente.name, status: cliente.status } : null, equipe);
    /* Sem preço ou sem carrinho, não há desconto para mostrar. */
    if (!visao.mostrarPreco || visao.modoDeCompra !== "cart") return NextResponse.json(VAZIO);

    const items = normalizarItens(body.items);
    const codigos = codigosDoCorpo(body);
    const disponiveis = await cuponsAVista(admin, loja.id).catch(() => []);
    if (!items.length) return NextResponse.json({ ...VAZIO, disponiveis });

    try {
      await conferirPrecosNoServidor(admin, loja.id, items);
    } catch (erro) {
      /* Item fora da loja: o carrinho já mostra o problema; o cupom espera. */
      return NextResponse.json({ ...VAZIO, disponiveis, erro: codigos.length ? (erro instanceof Error ? erro.message : null) : null });
    }

    const frete = body.shipping && Number.isFinite(Number(body.shipping.price))
      ? { valor: Math.max(Number(body.shipping.price) || 0, 0), cep: normalizeText(body.shipping.destination_zip), retirada: Boolean(body.shipping.pickup) }
      : null;
    const cupons = await calcularCuponsDoPedido(admin, {
      storeId: loja.id,
      codigos,
      items,
      cliente: cliente ? { id: cliente.id } : null,
      frete,
    });

    const agora = Date.now();
    const nomes = cupons.aplicados.length ? await nomesDoAlcance(admin, cupons.aplicados.map((a) => a.cupom)).catch(() => undefined) : undefined;
    const aplicados = cupons.aplicados.map((a) => ({
      code: a.code,
      nome: a.nome,
      tipo: a.cupom.type,
      vaga: a.vaga,
      automatico: a.automatico,
      desconto: a.desconto,
      descontoNoFrete: a.descontoNoFrete,
      esperandoFrete: a.esperandoFrete,
      rotulo: rotuloDoBeneficio(a.cupom),
      frase: fraseDoCupom(a.cupom, agora, nomes),
    }));
    return NextResponse.json({
      ok: true,
      aplicados,
      /* O formato de um cupom só (o carrinho de antes do deploy lê estes). */
      aplicado: aplicados.find((a) => a.vaga === "desconto") ?? aplicados[0] ?? null,
      aviso: cupons.avisos[0] ?? cupons.erros[0]?.mensagem ?? null,
      erro: cupons.erros[0]?.mensagem ?? null,
      avisos: cupons.avisos,
      erros: cupons.erros,
      digitados: cupons.digitados,
      disponiveis: disponiveis.filter((d) => !aplicados.some((a) => a.code === d.code)),
    });
  } catch {
    return NextResponse.json({ ...VAZIO, ok: false, erro: "Não foi possível conferir o cupom agora." }, { status: 500 });
  }
}
