import { NextResponse } from "next/server";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import {
  conteudoDaEmbalagem, converterCompra, formatoValido, FORMATOS,
} from "@/lib/precificacao/formato-de-compra";

/**
 * Entrada e ajuste de estoque do insumo.
 *
 * A entrada é o jeito natural de a empresa contar o que tem: "comprei um rolo
 * de 500 m por R$ 200". Ela soma o saldo E recalcula o custo por média
 * ponderada — a partir daí o custo do insumo é o que se pagou de verdade, e a
 * precificação lê esse número sem mudar nada. O ajuste é a contagem física:
 * define o saldo e registra o delta.
 *
 * As duas contas moram em funções do banco (`material_entrada` /
 * `material_ajuste`) para saldo e custo mudarem juntos, sem janela de corrida.
 * Aqui fica o que é da alçada da rota: permissão e dono.
 */

async function getAuth() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  return { supabase, user };
}

async function materialDaEmpresa(admin: ReturnType<typeof createAdminClient>, id: string, empresa: string) {
  const { data } = await admin
    .from("materials")
    .select("id,unit,purchase_format,roll_width_m,roll_length_m,package_qty,sheet_width_m,sheet_height_m")
    .eq("id", id)
    .eq("user_id", empresa)
    .maybeSingle();
  return data ?? null;
}

export async function POST(req: Request) {
  const { supabase, user } = await getAuth();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "materials.write")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const body = (await req.json().catch(() => null)) as Record<string, unknown> | null;
  const materialId = typeof body?.material_id === "string" ? body.material_id : "";
  const tipo = body?.tipo === "ajuste" ? "ajuste" : "entrada";
  const quantidade = Number(body?.quantidade);
  const custoUnitario = Number(body?.custo_unitario);
  const notas = typeof body?.notas === "string" && body.notas.trim() ? body.notas.trim() : null;

  if (!materialId) return NextResponse.json({ error: "Informe o insumo." }, { status: 400 });

  const admin = createAdminClient();
  /* O rpc não sabe de empresas; o dono se confere aqui. */
  const material = await materialDaEmpresa(admin, materialId, ctx.companyId);
  if (!material) {
    return NextResponse.json({ error: "Insumo não encontrado." }, { status: 404 });
  }

  if (tipo === "entrada") {
    let qtdFinal = quantidade;
    let custoFinal = custoUnitario;
    let notaFinal = notas;

    /* A entrada no idioma da compra: N embalagens a tanto cada. A conversão
       acontece AQUI, com as especificações do banco como fonte, para o dado
       chegar correto venha a chamada de onde vier. O `conteudo` do corpo
       permite ajustar a embalagem desta compra (a bobina de hoje pode ter
       outro comprimento); ausente, vale o cadastro. */
    const embalagens = Number(body?.embalagens);
    const precoEmbalagem = Number(body?.preco_embalagem);
    if (Number.isFinite(embalagens) && embalagens > 0) {
      const formato = formatoValido(material.purchase_format);
      const conteudoDoCorpo = Number(body?.conteudo);
      const conteudo = Number.isFinite(conteudoDoCorpo) && conteudoDoCorpo > 0
        ? conteudoDoCorpo
        : conteudoDaEmbalagem({
            formato,
            larguraM: material.roll_width_m,
            comprimentoM: material.roll_length_m,
            conteudoDaEmbalagem: material.package_qty,
            folhaLarguraM: material.sheet_width_m,
            folhaAlturaM: material.sheet_height_m,
          });
      const compra = converterCompra(embalagens, conteudo, precoEmbalagem);
      if (!compra) {
        return NextResponse.json(
          { error: `Informe o conteúdo de cada ${FORMATOS[formato].embalagem} e o preço pago.` },
          { status: 400 }
        );
      }
      qtdFinal = compra.quantidade;
      custoFinal = compra.custoUnitario;
      const descricao = `${embalagens} ${embalagens === 1 ? FORMATOS[formato].embalagem : FORMATOS[formato].embalagens} de ${conteudo} ${material.unit}`;
      notaFinal = notas ? `${descricao} — ${notas}` : descricao;
    }

    if (!Number.isFinite(qtdFinal) || qtdFinal <= 0) {
      return NextResponse.json({ error: "A quantidade da entrada deve ser maior que zero." }, { status: 400 });
    }
    if (!Number.isFinite(custoFinal) || custoFinal < 0) {
      return NextResponse.json({ error: "Informe quanto custou a compra." }, { status: 400 });
    }
    const { data, error } = await admin.rpc("material_entrada", {
      p_material: materialId,
      p_quantidade: qtdFinal,
      p_custo_unitario: custoFinal,
      p_notas: notaFinal,
    });
    if (error) return NextResponse.json({ error: error.message }, { status: 400 });
    return NextResponse.json({ ok: true, resultado: Array.isArray(data) ? data[0] : data });
  }

  if (!Number.isFinite(quantidade) || quantidade < 0) {
    return NextResponse.json({ error: "Informe o saldo contado." }, { status: 400 });
  }
  const { data, error } = await admin.rpc("material_ajuste", {
    p_material: materialId,
    p_novo_saldo: quantidade,
    p_notas: notas,
  });
  if (error) return NextResponse.json({ error: error.message }, { status: 400 });
  return NextResponse.json({ ok: true, resultado: Array.isArray(data) ? data[0] : data });
}

export async function GET(req: Request) {
  const { supabase, user } = await getAuth();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "materials.read")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const materialId = new URL(req.url).searchParams.get("material_id") ?? "";
  if (!materialId) return NextResponse.json({ error: "Informe o insumo." }, { status: 400 });

  const admin = createAdminClient();
  if (!(await materialDaEmpresa(admin, materialId, ctx.companyId))) {
    return NextResponse.json({ error: "Insumo não encontrado." }, { status: 404 });
  }

  const { data, error } = await admin
    .from("material_stock_movements")
    .select("id,kind,quantity,unit_cost,balance_after,reference_order_id,notes,created_at")
    .eq("material_id", materialId)
    .order("created_at", { ascending: false })
    .limit(50);
  if (error) return NextResponse.json({ error: error.message }, { status: 400 });

  return NextResponse.json({ movimentos: data ?? [] });
}
