import { NextResponse } from "next/server" import { z } from "zod" import { ConvexHttpClient } from "convex/browser" import { assertStaffSession } from "@/lib/auth-server" import type { Id } from "@/convex/_generated/dataModel" import { api } from "@/convex/_generated/api" export const runtime = "nodejs" const schema = z.object({ machineId: z.string().min(1), provider: z.string().optional(), identifier: z.string().optional(), url: z.string().optional(), notes: z.string().optional(), entryId: z.string().optional(), action: z.enum(["save", "upsert", "clear", "delete", "remove"]).optional(), }) export async function POST(request: Request) { const session = await assertStaffSession() if (!session) { return NextResponse.json({ error: "Não autorizado" }, { status: 401 }) } let parsed: z.infer try { const body = await request.json() parsed = schema.parse(body) } catch { return NextResponse.json({ error: "Payload inválido" }, { status: 400 }) } const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL if (!convexUrl) { return NextResponse.json({ error: "Convex não configurado" }, { status: 500 }) } const client = new ConvexHttpClient(convexUrl) try { const tenantId = session.user.tenantId ?? process.env.SYNC_TENANT_ID ?? process.env.SEED_USER_TENANT ?? "tenant-atlas" const ensured = (await client.mutation(api.users.ensureUser, { tenantId, email: session.user.email, name: session.user.name ?? session.user.email, avatarUrl: session.user.avatarUrl ?? undefined, role: session.user.role.toUpperCase(), })) as { _id?: Id<"users"> } | null const actorId = ensured?._id as Id<"users"> | undefined if (!actorId) { return NextResponse.json( { error: "Usuário não encontrado no Convex para executar esta ação." }, { status: 403 } ) } const actionRaw = (parsed.action ?? "save").toLowerCase() const normalizedAction = actionRaw === "clear" ? "clear" : actionRaw === "delete" || actionRaw === "remove" ? "delete" : "upsert" const provider = (parsed.provider ?? "").trim() const identifier = (parsed.identifier ?? "").trim() const notes = (parsed.notes ?? "").trim() let normalizedUrl: string | undefined if (normalizedAction === "upsert") { if (!provider || !identifier) { return NextResponse.json({ error: "Informe o provedor e o identificador do acesso remoto." }, { status: 400 }) } const rawUrl = (parsed.url ?? "").trim() if (rawUrl.length > 0) { const candidate = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}` try { new URL(candidate) normalizedUrl = candidate } catch { return NextResponse.json({ error: "URL inválida. Informe um endereço iniciado com http:// ou https://." }, { status: 422 }) } } } const mutationArgs: Record = { machineId: parsed.machineId as Id<"machines">, actorId, action: normalizedAction, } if (parsed.entryId) { mutationArgs.entryId = parsed.entryId } if (normalizedAction === "clear") { mutationArgs.clear = true } else { if (provider) mutationArgs.provider = provider if (identifier) mutationArgs.identifier = identifier if (normalizedUrl !== undefined) mutationArgs.url = normalizedUrl if (notes.length) mutationArgs.notes = notes } const result = (await (client as unknown as { mutation: (name: string, args: Record) => Promise }).mutation( "machines:updateRemoteAccess", mutationArgs )) as { remoteAccess?: unknown } | null return NextResponse.json({ ok: true, remoteAccess: result?.remoteAccess ?? null }) } catch (error) { console.error("[machines.remote-access]", error) const detail = error instanceof Error ? error.message : null const isOutdatedConvex = typeof detail === "string" && detail.includes("extra field `action`") if (isOutdatedConvex) { return NextResponse.json( { error: "Backend do Convex desatualizado", detail: "Recompile/deploy as funções Convex (ex.: `bun run convex:dev:bun` em desenvolvimento ou `bun x convex deploy`) para aplicar o suporte a múltiplos acessos remotos.", }, { status: 409 } ) } return NextResponse.json( { error: "Falha ao atualizar acesso remoto", ...(process.env.NODE_ENV !== "production" && detail ? { detail } : {}), }, { status: 500 } ) } }