import { NextResponse } from "next/server";
import { abrirEstoque, exigirV2, respostaDoErro, textoOuNulo, numeroOuNulo, UUID } from "@/lib/estoque/servidor";
import { lerItens } from "@/lib/estoque/leituras.server";
import { gradeValida } from "@/lib/estoque/regras";

/* Os itens do estoque (insumos e produtos prontos), cada um com as células e
   quem usa. GET ?papel=insumo|pronto&id=<item> */
export async function GET(req: Request) {
  const r = await abrirEstoque(["products.stock.read", "materials.read"]);
  if (!r.ok) return r.resposta;
  const falta = exigirV2(r.e);
  if (falta) return falta;
  const url = new URL(req.url);
  const papel = url.searchParams.get("papel");
  const id = url.searchParams.get("id");
  const itens = await lerItens(r.e, {
    papel: papel === "insumo" || papel === "pronto" ? papel : null,
    ids: id && UUID.test(id) ? [id] : null,
    comUsos: true,
  });
  return NextResponse.json({ itens });
}

/* Cria ou altera um item (estoque_salvar_item). A grade vai inteira: o banco
   recusa tirar da grade célula que ainda tem saldo. */
export async function POST(req: Request) {
  const r = await abrirEstoque("materials.write");
  if (!r.ok) return r.resposta;
  const falta = exigirV2(r.e);
  if (falta) return falta;
  const corpo = (await req.json().catch(() => null)) as Record<string, unknown> | null;
  if (!corpo) return NextResponse.json({ error: "Nada para salvar." }, { status: 400 });

  const id = typeof corpo.id === "string" && UUID.test(corpo.id) ? corpo.id : null;
  const p: Record<string, unknown> = {};
  if (id) p.id = id;
  else p.empresa = r.e.dono;

  const nome = textoOuNulo(corpo.nome, 160);
  if (!id && !nome) return NextResponse.json({ error: "Dê um nome ao item." }, { status: 400 });
  if (nome) p.nome = nome;
  const unidade = textoOuNulo(corpo.unidade, 20);
  if (unidade) p.unidade = unidade;
  if (corpo.papel === "insumo" || corpo.papel === "pronto") p.papel = corpo.papel;
  if ("grade" in corpo) {
    p.grade = gradeValida(corpo.grade).map((e) => ({
      nome: e.nome.trim(),
      valores: e.valores.map((v) => v.trim()).filter(Boolean),
    }));
  }
  if ("minimo" in corpo) p.minimo = numeroOuNulo(corpo.minimo);
  if ("perda" in corpo) p.perda = numeroOuNulo(corpo.perda) ?? 0;
  if (typeof corpo.permitir_negativo === "boolean") p.permitir_negativo = corpo.permitir_negativo;
  if (typeof corpo.controla === "boolean") p.controla = corpo.controla;
  if (Array.isArray(corpo.conversoes)) {
    p.conversoes = (corpo.conversoes as Array<Record<string, unknown>>)
      .map((c) => ({ unidade: textoOuNulo(c?.unidade, 20), fator: numeroOuNulo(c?.fator) }))
      .filter((c) => c.unidade && c.fator && c.fator > 0)
      .slice(0, 10);
  }
  if (!id && "custo" in corpo) p.custo = numeroOuNulo(corpo.custo) ?? 0;
  if ("produto_id" in corpo) p.produto_id = typeof corpo.produto_id === "string" && UUID.test(corpo.produto_id) ? corpo.produto_id : null;

  /* Item de outra empresa nunca: o banco confere a permissão pelo dono do
     item, e aqui o filtro da empresa fecha o resto. */
  if (id) {
    const { data: meu } = await r.e.admin.from("materials").select("id").eq("id", id).in("user_id", r.e.ids).maybeSingle();
    if (!meu) return NextResponse.json({ error: "Item não encontrado." }, { status: 404 });
  }

  const { data, error } = await r.e.supabase.rpc("estoque_salvar_item", { p });
  if (error) return respostaDoErro(error);
  const salvo = data as { item?: { id?: string } } | null;
  const itemId = salvo?.item?.id;
  const itens = itemId ? await lerItens(r.e, { ids: [itemId], comUsos: true }) : [];
  return NextResponse.json({ item: itens[0] ?? null });
}
