/*
 * Estoque v2 — o começo de toda rota do estoque no painel.
 *
 * Quem fala com o banco nas MUDANÇAS é o cliente da sessão da pessoa
 * (`supabase`): as funções do motor são SECURITY DEFINER e conferem a
 * permissão pelo `auth.uid()`. As LEITURAS de tabela usam o cliente de
 * serviço (`admin`) depois de a rota conferir a chave, porque o RLS de
 * `materials` só deixa o dono ler (a equipe chegaria vazia), e cada consulta
 * leva o filtro da empresa (`ids`).
 */

import { NextResponse } from "next/server";
import type { SupabaseClient, User } from "@supabase/supabase-js";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { canCompany, getCompanyContext, type CompanyContext, type CompanyPermission } from "@/lib/company-context";
import { numeroDoTexto } from "@/lib/numero-do-campo";

export type ContextoDoEstoque = {
  supabase: SupabaseClient;
  admin: SupabaseClient;
  user: User;
  ctx: CompanyContext;
  /** O dono (owner id): a "empresa" das funções do estoque. */
  dono: string;
  /** Todos os ids que a empresa usa em `user_id` (dono e empresa). */
  ids: string[];
  v2: boolean;
};

type Resultado = { ok: true; e: ContextoDoEstoque } | { ok: false; resposta: NextResponse };

export async function abrirEstoque(permissao?: CompanyPermission | CompanyPermission[]): Promise<Resultado> {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return { ok: false, resposta: NextResponse.json({ error: "Entre de novo no painel." }, { status: 401 }) };
  const ctx = await getCompanyContext(supabase, user);
  const chaves = permissao ? (Array.isArray(permissao) ? permissao : [permissao]) : [];
  if (chaves.length && !chaves.some((c) => canCompany(ctx, user.id, c))) {
    return { ok: false, resposta: NextResponse.json({ error: "Sem permissão para esta parte do estoque." }, { status: 403 }) };
  }
  const dono = ctx.ownerId ?? ctx.companyId;
  const admin = createAdminClient();
  const { data } = await admin.rpc("estoque_v2_ligado", { p_empresa: dono });
  const ids = Array.from(new Set([dono, ctx.companyId, ...(ctx.tenantIds ?? [])].filter(Boolean)));
  return { ok: true, e: { supabase, admin, user, ctx, dono, ids, v2: data === true } };
}

/** Rota que só faz sentido no estoque novo. */
export function exigirV2(e: ContextoDoEstoque): NextResponse | null {
  if (e.v2) return null;
  return NextResponse.json({ error: "O estoque novo ainda não está ligado nesta empresa." }, { status: 409 });
}

/** O erro do banco como a tela entende: mensagem em português + código (hint). */
export function respostaDoErro(erro: { message?: string; hint?: string; details?: string } | null, status = 400) {
  return NextResponse.json(
    { error: erro?.message || "Não deu certo. Tente de novo.", hint: erro?.hint || null, details: erro?.details || null },
    { status }
  );
}

export function textoOuNulo(v: unknown, max = 500): string | null {
  const t = typeof v === "string" ? v.trim() : "";
  return t ? t.slice(0, max) : null;
}

export function numeroOuNulo(v: unknown): number | null {
  if (typeof v === "number") return Number.isFinite(v) ? v : null;
  if (typeof v === "string" && /\d/.test(v)) return numeroDoTexto(v);
  return null;
}

export const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

/** O produto é desta empresa? (as rotas nunca confiam no id que veio da tela) */
export async function produtoDaEmpresa(e: ContextoDoEstoque, produtoId: string) {
  if (!UUID.test(produtoId)) return null;
  const { data } = await e.admin
    .from("products")
    .select("id,name,user_id,estoque_modo,estoque_item_id,estoque_mapa,track_inventory,allow_negative_stock,inventory_scope,unit_type,image_url,product_kind")
    .eq("id", produtoId)
    .in("user_id", e.ids)
    .maybeSingle();
  return data as
    | {
        id: string;
        name: string;
        user_id: string;
        estoque_modo: string | null;
        estoque_item_id: string | null;
        estoque_mapa: unknown;
        track_inventory: boolean | null;
        allow_negative_stock: boolean | null;
        inventory_scope: string | null;
        unit_type: string | null;
        image_url: string | null;
        product_kind: string | null;
      }
    | null;
}
