/*
  Conferir o estoque ANTES de cobrar.

  O pagamento aprovado vira pedido sozinho. Se o estoque tinha acabado no
  meio do caminho, o pedido não nascia e o cliente ficava pago sem pedido.
  Agora, antes de mandar a cobrança, o servidor pergunta ao banco se o
  carrinho inteiro cabe (estoque_conferir_itens, a MESMA conta da loja, do
  PDV e do orçamento — soma por célula, e fora do estoque v2 a regra antiga
  de produto/combinação/opção). Cabe: segue. Não cabe: o cliente volta ao
  carrinho com a razão. E se ainda assim faltar entre a conferência e a
  aprovação, o pedido da loja nasce marcado como "venda já paga" e vira
  reposição pendente — nunca pagamento sem pedido.

  Falha do próprio banco ao conferir não trava a venda: a trava da criação
  do pedido continua valendo.

  No estoque v2 a frase ao cliente diz o produto e a combinação dele
  ("Camiseta (G / Preta): esgotado."), nunca o insumo da composição; fora
  do v2 segue a frase de sempre do banco.
*/

import { avisosDoCarrinho, fraseDoCarrinho, problemasDoV2 } from "./estoque-v2-da-loja.ts";
import { conferirItensNoBanco } from "./conferir-itens.ts";

type Rpc = {
  rpc: (fn: string, params: Record<string, unknown>) => PromiseLike<{ data: unknown; error: { message?: string } | null }>;
};

export type ItemParaConferir = {
  product_id?: string | null;
  quantity?: number | string | null;
  selected_options?: unknown;
  width_m?: number | string | null;
  height_m?: number | string | null;
  title?: string | null;
};

type Problema = { indice?: number; mensagem?: string; titulo?: string; disponivel?: number; celula_id?: string | null };

export function itensParaConferir(itens: ItemParaConferir[] | null | undefined) {
  return (Array.isArray(itens) ? itens : [])
    .filter((item) => typeof item?.product_id === "string" && item.product_id.length > 0 && Number(item.quantity || 0) > 0)
    .map((item) => ({
      product_id: item.product_id,
      quantity: Number(item.quantity || 0),
      selected_options:
        item.selected_options && typeof item.selected_options === "object" && !Array.isArray(item.selected_options)
          ? item.selected_options
          : null,
      width_m: Number(item.width_m || 0) || null,
      height_m: Number(item.height_m || 0) || null,
      title: item.title ? String(item.title) : null,
    }));
}

/** A frase para o cliente quando o carrinho não cabe; null quando cabe. */
export function mensagemDosProblemas(problemas: Problema[] | null | undefined): string | null {
  const lista = (Array.isArray(problemas) ? problemas : []).filter((p) => p && typeof p.mensagem === "string" && p.mensagem);
  if (!lista.length) return null;
  const primeiras = lista.slice(0, 2).map((p) => String(p.mensagem));
  const resto = lista.length > 2 ? ` E mais ${lista.length - 2} item(ns).` : "";
  return `${primeiras.join(" ")}${resto} Ajuste o carrinho e tente de novo.`;
}

export async function conferirEstoqueAntesDeCobrar(
  admin: Rpc,
  donoDaLoja: string,
  itens: ItemParaConferir[] | null | undefined
): Promise<string | null> {
  const lista = itensParaConferir(itens);
  if (!lista.length || !donoDaLoja) return null;
  let resposta: { ok?: boolean; problemas?: Problema[] } | null = null;
  try {
    resposta = await conferirItensNoBanco(admin, donoDaLoja, lista as never);
  } catch (erro) {
    console.error("[loja] não foi possível conferir o estoque antes de cobrar:", erro instanceof Error ? erro.message : erro);
    return null;
  }
  if (!resposta) {
    console.error("[loja] não foi possível conferir o estoque antes de cobrar.");
    return null;
  }
  if (!resposta || resposta.ok !== false) return null;
  if (problemasDoV2(resposta.problemas)) {
    const frase = fraseDoCarrinho(avisosDoCarrinho(resposta.problemas, lista));
    if (frase) return frase;
  }
  return mensagemDosProblemas(resposta.problemas) ?? "Um dos itens não tem estoque suficiente. Ajuste o carrinho e tente de novo.";
}
