import { NextResponse } from "next/server";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";

/**
 * O que está acabando, e de quem comprar.
 *
 * O insumo já tinha o campo "avisar abaixo de" desde sempre, e ele não avisava
 * ninguém: era um número guardado. Com o vínculo insumo × fornecedor, ele vira
 * a pergunta que se responde toda semana — "o que preciso comprar, e de quem?".
 *
 * A sugestão de quantidade é simples de propósito: o que falta para voltar ao
 * dobro do mínimo. Chutar consumo médio exigiria uma janela de tempo que
 * ninguém configurou, e um número inventado é pior do que um número redondo
 * que a pessoa ajusta na hora de pedir.
 */

async function getAuth() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return { ok: false as const, status: 401, ctx: null };
  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "materials.read")) return { ok: false as const, status: 403, ctx: null };
  return { ok: true as const, status: 200, ctx };
}

export async function GET() {
  const auth = await getAuth();
  if (!auth.ok || !auth.ctx) {
    return NextResponse.json({ error: auth.status === 401 ? "Não autenticado." : "Sem permissão." }, { status: auth.status });
  }

  const admin = createAdminClient();
  const companyId = auth.ctx.companyId;

  const { data: insumos, error } = await admin
    .from("materials")
    .select("id,name,unit,current_stock,min_stock_alert,cost_per_unit")
    .eq("user_id", companyId)
    .eq("track_stock", true)
    .not("min_stock_alert", "is", null)
    .neq("is_active", false);

  if (error) {
    return NextResponse.json({ error: "Falha ao conferir o estoque." }, { status: 500 });
  }

  const abaixoDoMinimo = (insumos ?? []).filter(
    (insumo) => Number(insumo.current_stock || 0) <= Number(insumo.min_stock_alert || 0)
  );

  if (abaixoDoMinimo.length === 0) {
    return NextResponse.json({ ok: true, itens: [], porFornecedor: [] });
  }

  const idsDosInsumos = abaixoDoMinimo.map((insumo) => String(insumo.id));

  const { data: vinculos } = await admin
    .from("supplier_materials")
    .select("supplier_id,linked_material_id,name,last_unit_price,lead_time_days,preferred")
    .eq("company_id", companyId)
    .in("linked_material_id", idsDosInsumos)
    .is("deleted_at", null);

  const idsDeFornecedor = Array.from(
    new Set((vinculos ?? []).map((v) => String(v.supplier_id)).filter(Boolean))
  );

  const fornecedores = new Map<string, string>();
  if (idsDeFornecedor.length > 0) {
    const { data: linhas } = await admin
      .from("suppliers")
      .select("id,name")
      .eq("company_id", companyId)
      .in("id", idsDeFornecedor)
      .eq("status", "ativo")
      .is("deleted_at", null);
    for (const linha of linhas ?? []) fornecedores.set(String(linha.id), String(linha.name || ""));
  }

  /* O preferido manda; sem preferido, o mais barato da última compra; sem
     preço, o primeiro que aparecer. */
  const melhorPorInsumo = new Map<string, { supplierId: string; supplierName: string; preco: number; prazo: number | null }>();
  for (const vinculo of vinculos ?? []) {
    const insumoId = String(vinculo.linked_material_id);
    const nome = fornecedores.get(String(vinculo.supplier_id));
    if (!nome) continue;

    const candidato = {
      supplierId: String(vinculo.supplier_id),
      supplierName: nome,
      preco: Number(vinculo.last_unit_price || 0),
      prazo: vinculo.lead_time_days === null || vinculo.lead_time_days === undefined ? null : Number(vinculo.lead_time_days),
      preferido: vinculo.preferred === true,
    };

    const atual = melhorPorInsumo.get(insumoId) as (typeof candidato) | undefined;
    if (!atual) {
      melhorPorInsumo.set(insumoId, candidato);
      continue;
    }
    if (candidato.preferido && !atual.preferido) {
      melhorPorInsumo.set(insumoId, candidato);
      continue;
    }
    if (!atual.preferido && candidato.preco > 0 && (atual.preco === 0 || candidato.preco < atual.preco)) {
      melhorPorInsumo.set(insumoId, candidato);
    }
  }

  const itens = abaixoDoMinimo.map((insumo) => {
    const minimo = Number(insumo.min_stock_alert || 0);
    const saldo = Number(insumo.current_stock || 0);
    const sugerido = Math.max(0, Math.round((minimo * 2 - saldo) * 1000) / 1000);
    const fornecedor = melhorPorInsumo.get(String(insumo.id)) ?? null;
    return {
      id: String(insumo.id),
      name: String(insumo.name || ""),
      unit: String(insumo.unit || "un"),
      currentStock: saldo,
      minStockAlert: minimo,
      quantidadeSugerida: sugerido,
      custoEstimado: fornecedor && fornecedor.preco > 0 ? Math.round(sugerido * fornecedor.preco * 100) / 100 : null,
      supplierId: fornecedor?.supplierId ?? null,
      supplierName: fornecedor?.supplierName ?? null,
      leadTimeDays: fornecedor?.prazo ?? null,
    };
  });

  /* Agrupado por fornecedor porque é assim que a compra acontece: uma ligação
     para cada um, com a lista do que pedir. */
  const agrupado = new Map<string, { supplierId: string; supplierName: string; itens: typeof itens; total: number }>();
  for (const item of itens) {
    if (!item.supplierId) continue;
    const atual = agrupado.get(item.supplierId) ?? {
      supplierId: item.supplierId,
      supplierName: item.supplierName ?? "",
      itens: [] as typeof itens,
      total: 0,
    };
    atual.itens.push(item);
    atual.total += item.custoEstimado ?? 0;
    agrupado.set(item.supplierId, atual);
  }

  return NextResponse.json({
    ok: true,
    itens,
    semFornecedor: itens.filter((item) => !item.supplierId).length,
    porFornecedor: Array.from(agrupado.values()).sort((a, b) => b.itens.length - a.itens.length),
  });
}
