import { NextResponse } from "next/server";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { numeroDoTexto } from "@/lib/numero-do-campo";
import { sugerirInsumo, type InsumoParaCasar } from "@/lib/fornecedores/casar-insumo";

/**
 * O que este fornecedor vende, e qual insumo do meu catalogo cada item
 * abastece.
 *
 * Duas coisas nasceram aqui. A primeira: nao existia POST em lugar nenhum, e
 * material de fornecedor so passava a existir como efeito colateral de
 * registrar uma compra. Para cadastrar um item de catalogo, a pessoa tinha que
 * inventar uma compra. A segunda: o vinculo com o insumo de verdade, que e o
 * que faz o modulo deixar de ser uma segunda lista de materiais.
 */

type Params = { params: Promise<{ id: string }> };

function texto(valor: unknown) {
  return typeof valor === "string" ? valor.trim() : "";
}

function inteiroOuNulo(valor: unknown) {
  if (valor === null || valor === undefined || valor === "") return null;
  const n = typeof valor === "number" ? valor : numeroDoTexto(String(valor));
  if (!Number.isFinite(n) || n < 0) return null;
  return Math.trunc(n);
}

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

async function registrarNoHistorico(
  admin: ReturnType<typeof createAdminClient>,
  companyId: string,
  supplierId: string,
  actorUserId: string | null,
  action: string,
  description: string,
  payload: Record<string, unknown>
) {
  await admin.from("supplier_activity_log").insert({
    company_id: companyId,
    supplier_id: supplierId,
    entity_type: "supplier",
    entity_id: supplierId,
    action,
    description,
    payload,
    actor_user_id: actorUserId,
  });
}

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

  const { id } = await params;
  const admin = createAdminClient();
  const companyId = auth.ctx.companyId;

  const [{ data: supplier }, { data: materiais, error }, { data: insumos }] = await Promise.all([
    admin.from("suppliers").select("id,name").eq("company_id", companyId).eq("id", id).is("deleted_at", null).maybeSingle(),
    admin
      .from("supplier_materials")
      .select(
        "id,name,sku,unit,purchase_unit,notes,last_unit_price,last_purchase_at,linked_material_id,lead_time_days,preferred,created_at"
      )
      .eq("company_id", companyId)
      .eq("supplier_id", id)
      .is("deleted_at", null)
      .order("name", { ascending: true }),
    /* `materials.user_id` guarda o id da empresa: e a mesma chave de
       `suppliers.company_id`, conferido nos 606 insumos em producao. */
    admin
      .from("materials")
      .select("id,name,unit,cost_per_unit,current_stock,track_stock,min_stock_alert,purchase_format,is_active")
      .eq("user_id", companyId)
      .order("name", { ascending: true }),
  ]);

  if (!supplier?.id) return NextResponse.json({ error: "Fornecedor não encontrado." }, { status: 404 });
  if (error) return NextResponse.json({ error: "Falha ao carregar os itens do fornecedor." }, { status: 500 });

  const catalogo = (insumos ?? []) as InsumoParaCasar[];
  const insumoPorId = new Map(catalogo.map((item) => [String(item.id), item]));

  return NextResponse.json({
    ok: true,
    supplier: { id: String(supplier.id), name: String(supplier.name || "") },
    materials: (materiais ?? []).map((item) => {
      const ligado = item.linked_material_id ? insumoPorId.get(String(item.linked_material_id)) ?? null : null;
      /* Para quem ainda nao ligou, a sugestao pelo nome. E o que transforma a
         migracao dos 72 registros existentes numa tela de confirmar, e nao num
         trabalho de digitar tudo de novo. */
      const sugestao = ligado ? null : sugerirInsumo(String(item.name || ""), catalogo);
      return {
        id: String(item.id),
        name: String(item.name || ""),
        sku: item.sku ?? null,
        unit: String(item.unit || "un"),
        purchaseUnit: item.purchase_unit ?? null,
        notes: item.notes ?? null,
        lastUnitPrice: Number(item.last_unit_price || 0),
        lastPurchaseAt: item.last_purchase_at ?? null,
        leadTimeDays: item.lead_time_days ?? null,
        preferred: item.preferred === true,
        linkedMaterial: ligado
          ? {
              id: String(ligado.id),
              name: String(ligado.name || ""),
              unit: String(ligado.unit || "un"),
              costPerUnit: Number(ligado.cost_per_unit || 0),
              currentStock: Number(ligado.current_stock || 0),
              trackStock: ligado.track_stock === true,
            }
          : null,
        sugestao: sugestao
          ? { id: String(sugestao.insumo.id), name: String(sugestao.insumo.name || ""), confianca: sugestao.confianca }
          : null,
      };
    }),
    insumos: catalogo
      .filter((item) => item.is_active !== false)
      .map((item) => ({
        id: String(item.id),
        name: String(item.name || ""),
        unit: String(item.unit || "un"),
        costPerUnit: Number(item.cost_per_unit || 0),
        currentStock: Number(item.current_stock || 0),
        trackStock: item.track_stock === true,
        minStockAlert: item.min_stock_alert === null || item.min_stock_alert === undefined ? null : Number(item.min_stock_alert),
      })),
  });
}

export async function POST(req: Request, { params }: Params) {
  const auth = await getAuth("suppliers.list.write");
  if (!auth.ok || !auth.ctx) {
    return NextResponse.json({ error: auth.status === 401 ? "Não autenticado." : "Sem permissão." }, { status: auth.status });
  }

  const { id } = await params;
  const body = (await req.json().catch(() => null)) as Record<string, unknown> | null;

  const nome = texto(body?.name);
  if (!nome) return NextResponse.json({ error: "Informe o nome do item." }, { status: 400 });

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

  const { data: supplier } = await admin
    .from("suppliers")
    .select("id,name")
    .eq("company_id", companyId)
    .eq("id", id)
    .is("deleted_at", null)
    .maybeSingle();

  if (!supplier?.id) return NextResponse.json({ error: "Fornecedor não encontrado." }, { status: 404 });

  const linkedMaterialId = texto(body?.linkedMaterialId) || null;
  if (linkedMaterialId) {
    const { data: insumo } = await admin
      .from("materials")
      .select("id")
      .eq("user_id", companyId)
      .eq("id", linkedMaterialId)
      .maybeSingle();
    if (!insumo?.id) return NextResponse.json({ error: "Esse insumo não é da sua empresa." }, { status: 400 });
  }

  const { data: criado, error } = await admin
    .from("supplier_materials")
    .insert({
      company_id: companyId,
      supplier_id: id,
      name: nome,
      sku: texto(body?.sku) || null,
      unit: texto(body?.unit) || "un",
      purchase_unit: texto(body?.purchaseUnit) || null,
      notes: texto(body?.notes) || null,
      linked_material_id: linkedMaterialId,
      lead_time_days: inteiroOuNulo(body?.leadTimeDays),
      last_unit_price: Math.max(0, numeroDoTexto(String(body?.lastUnitPrice ?? "0"))),
      created_by: auth.user?.id ?? null,
    })
    .select("id")
    .single();

  if (error || !criado?.id) {
    /* O indice unico por nome e o indice unico por insumo caem os dois aqui. */
    const duplicado = String(error?.code || "") === "23505";
    return NextResponse.json(
      { error: duplicado ? "Esse fornecedor já tem um item com esse nome ou ligado a esse insumo." : "Falha ao cadastrar o item." },
      { status: duplicado ? 400 : 500 }
    );
  }

  await registrarNoHistorico(
    admin,
    companyId,
    id,
    auth.user?.id ?? null,
    "material.created",
    `Item ${nome} cadastrado em ${supplier.name || "fornecedor"}.`,
    { materialId: criado.id, linkedMaterialId }
  );

  return NextResponse.json({ ok: true, id: String(criado.id) });
}
