import { NextResponse } from "next/server";
import { abrirEstoque, exigirV2, respostaDoErro, UUID } from "@/lib/estoque/servidor";
import type { Movimento } from "@/lib/estoque/tipos";

/*
 * A linha do tempo (estoque_historico) da empresa, de um item ou de uma
 * célula. GET ?item=&celula=&antes=<em do último>&limite=
 *
 * A origem do banco já traz pedido e compra; aqui ela ganha o que falta para
 * virar link: o fornecedor da compra, o pedido da perda, se a produção foi
 * desfeita, e o nome de quem lançou.
 */
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 item = url.searchParams.get("item");
  const celula = url.searchParams.get("celula");
  const antes = url.searchParams.get("antes");
  const limite = Math.min(200, Math.max(1, Number(url.searchParams.get("limite")) || 60));

  const { data, error } = await r.e.supabase.rpc("estoque_historico", {
    p_empresa: r.e.dono,
    p_item: item && UUID.test(item) ? item : null,
    p_celula: celula && UUID.test(celula) ? celula : null,
    p_limite: limite,
    p_antes: antes && !Number.isNaN(Date.parse(antes)) ? antes : null,
  });
  if (error) return respostaDoErro(error);
  const movimentos = ((data as Movimento[] | null) ?? []).map((m) => ({ ...m, quantidade: Number(m.quantidade), saldo_depois: Number(m.saldo_depois) }));

  const compras = Array.from(new Set(movimentos.map((m) => m.origem?.compra_id).filter((x): x is string => Boolean(x))));
  const perdas = Array.from(new Set(movimentos.map((m) => m.origem?.perda_id).filter((x): x is string => Boolean(x))));
  const producoes = Array.from(new Set(movimentos.map((m) => m.origem?.producao_id).filter((x): x is string => Boolean(x))));
  const pessoas = Array.from(new Set(movimentos.map((m) => m.por).filter((x): x is string => Boolean(x))));

  const [rc, rp, rpr, rpe] = await Promise.all([
    compras.length
      ? r.e.admin.from("supplier_purchase_orders").select("id,supplier_id").in("id", compras).in("company_id", r.e.ids)
      : Promise.resolve({ data: [] }),
    perdas.length
      ? r.e.admin.from("order_production_losses").select("id,order_id,orders(number)").in("id", perdas)
      : Promise.resolve({ data: [] }),
    producoes.length
      ? r.e.admin.from("estoque_producoes").select("id,desfeita_em,produto_id").in("id", producoes).eq("empresa_id", r.e.dono)
      : Promise.resolve({ data: [] }),
    pessoas.length
      ? r.e.admin.from("employee_profiles").select("user_id,full_name").in("user_id", pessoas)
      : Promise.resolve({ data: [] }),
  ]);
  const fornecedor = new Map(((rc.data as Array<{ id: string; supplier_id: string }> | null) ?? []).map((c) => [c.id, c.supplier_id]));
  const perda = new Map(
    ((rp.data as unknown as Array<{ id: string; order_id: string | null; orders: { number: number | null } | null }> | null) ?? []).map((p) => [p.id, p])
  );
  const producao = new Map(((rpr.data as Array<{ id: string; desfeita_em: string | null; produto_id: string }> | null) ?? []).map((p) => [p.id, p]));
  const nome = new Map(((rpe.data as Array<{ user_id: string; full_name: string | null }> | null) ?? []).map((p) => [p.user_id, p.full_name]));

  for (const m of movimentos) {
    const o = (m.origem ??= {});
    if (o.compra_id && fornecedor.has(o.compra_id)) o.fornecedor_id = fornecedor.get(o.compra_id);
    if (o.perda_id && perda.has(o.perda_id)) {
      const p = perda.get(o.perda_id)!;
      o.perda_pedido_id = p.order_id ?? undefined;
      o.perda_pedido_numero = p.orders?.number ?? undefined;
    }
    if (o.producao_id && producao.has(o.producao_id)) {
      o.producao_desfeita = Boolean(producao.get(o.producao_id)!.desfeita_em);
      o.producao_produto_id = producao.get(o.producao_id)!.produto_id;
    }
    m.por_nome = m.por ? (m.por === r.e.dono ? "Empresa" : nome.get(m.por) ?? null) : null;
  }

  return NextResponse.json({ movimentos, mais: movimentos.length === limite });
}
