import {
  conferirEstoqueDaVenda,
  faltasDaDisponibilidade,
  textoDoDisponivel,
  type Disponibilidade,
} from "@/lib/estoque-da-venda";

import type { ContextoDoAssistente } from "../contexto";

/*
  O estoque v2 visto pelas ferramentas do assistente (orçamento, preço,
  produto): a MESMA conta da loja, do PDV e das telas, no banco
  (estoque_disponivel / estoque_conferir_itens), pela sessão da pessoa.
  Fora do v2 as ferramentas seguem com o aviso de sempre (avisoDeEstoque).
*/

const ligadas = new WeakMap<ContextoDoAssistente, Promise<boolean>>();

/** A empresa desta conversa está no estoque v2? (uma pergunta por chamada) */
export function empresaNoEstoqueV2(ctx: ContextoDoAssistente): Promise<boolean> {
  let pergunta = ligadas.get(ctx);
  if (!pergunta) {
    pergunta = Promise.resolve(ctx.supabase.rpc("estoque_v2_ligado", { p_empresa: ctx.donoDosDados })).then(
      ({ data, error }) => !error && data === true
    );
    ligadas.set(ctx, pergunta);
  }
  return pergunta;
}

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

/**
 * As faltas do orçamento inteiro (somando por célula), em aviso por item:
 * 'Item 2 (Camisetas): Acabou o estoque de "Camiseta lisa (G / Preta)" para
 * "Camisetas": tem 0, o pedido precisa de 3.' Só aviso: orçamento salva.
 */
export async function avisosDoEstoqueV2(ctx: ContextoDoAssistente, linhas: LinhaComEstoque[]): Promise<string[]> {
  const { faltas } = await conferirEstoqueDaVenda(
    ctx.supabase,
    ctx.donoDosDados,
    linhas.map((linha) => ({
      product_id: linha.product_id ?? null,
      quantity: linha.quantity ?? 0,
      selected_options: linha.selected_options ?? null,
      width_m: linha.width_m ?? null,
      height_m: linha.height_m ?? null,
      title: linha.title ?? null,
    }))
  );
  const avisos: string[] = [];
  for (const [indice, frases] of Array.from(faltas.entries()).sort((a, b) => a[0] - b[0])) {
    const titulo = linhas[indice]?.title ? ` (${linhas[indice]?.title})` : "";
    avisos.push(`Item ${indice + 1}${titulo}: ${frases.join(" ")} Ao gerar o pedido, o estoque recusa — lance a entrada antes ou ligue "permitir negativo" no item.`);
  }
  return avisos;
}

/** A disponibilidade de uma escolha (calcular_preco, ver_estoque_do_produto). */
export async function disponibilidadeNoBanco(
  ctx: ContextoDoAssistente,
  params: { produtoId: string; selected: unknown; quantidade: number; largura?: number | null; altura?: number | null }
): Promise<Disponibilidade | null> {
  const { data, error } = await ctx.supabase.rpc("estoque_disponivel", {
    p_produto: params.produtoId,
    p_selected_options: params.selected && typeof params.selected === "object" ? params.selected : null,
    p_quantidade: params.quantidade > 0 ? params.quantidade : 1,
    p_largura: params.largura && params.largura > 0 ? params.largura : null,
    p_altura: params.altura && params.altura > 0 ? params.altura : null,
    p_maximo: true,
  });
  if (error || !data) return null;
  return data as Disponibilidade;
}

/** O resumo que as ferramentas devolvem sobre o estoque de uma escolha. */
export function resumoDoEstoque(d: Disponibilidade | null) {
  if (!d) return null;
  return {
    de_onde_sai: d.modo ?? null,
    controla: d.controla === true,
    limita_a_venda: d.limita === true,
    da_para_vender_agora: d.limita ? Math.max(Number(d.disponivel ?? 0), 0) : "sem limite",
    cabe: d.cabe !== false,
    ao_vender_sai: (d.itens || []).map((item) => ({
      item: item.rotulo || item.nome,
      precisa: item.precisa,
      tem: item.saldo,
      unidade: item.unidade ?? null,
      vende_sem_saldo: item.permite_negativo !== false,
      ...(item.sem_celula ? { falta_escolher: item.falta_escolher || "a variação" } : {}),
    })),
    faltas: faltasDaDisponibilidade(d),
    texto: textoDoDisponivel(d),
  };
}
