import { NextRequest, NextResponse } from "next/server" import { cookies } from "next/headers" import { ConvexHttpClient } from "convex/browser" import { api } from "@/convex/_generated/api" import type { Id } from "@/convex/_generated/dataModel" import { env } from "@/lib/env" import { assertAuthenticatedSession } from "@/lib/auth-server" import { DEFAULT_TENANT_ID } from "@/lib/constants" const MACHINE_CTX_COOKIE = "machine_ctx" // Força runtime Node.js para leitura consistente de cookies de sessão export const runtime = "nodejs" type CollaboratorMetadata = { email: string name: string | null role: "collaborator" | "manager" | null } function decodeMachineCookie(value: string) { try { const json = Buffer.from(value, "base64url").toString("utf8") return JSON.parse(json) as { machineId: string persona: string | null assignedUserId: string | null assignedUserEmail: string | null assignedUserName: string | null assignedUserRole: string | null } } catch { return null } } function encodeMachineCookie(payload: { machineId: string persona: string | null assignedUserId: string | null assignedUserEmail: string | null assignedUserName: string | null assignedUserRole: string | null }) { return Buffer.from(JSON.stringify(payload)).toString("base64url") } function extractCollaboratorFromMetadata(metadata: unknown): CollaboratorMetadata | null { if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) { return null } const record = metadata as Record const raw = record["collaborator"] if (!raw || typeof raw !== "object" || Array.isArray(raw)) { return null } const base = raw as Record const emailValue = base["email"] if (typeof emailValue !== "string") { return null } const email = emailValue.trim().toLowerCase() if (!email) { return null } const nameValue = base["name"] const roleValue = base["role"] const name = typeof nameValue === "string" ? (nameValue.trim() || null) : null const normalizedRole = typeof roleValue === "string" ? roleValue.trim().toLowerCase() : null const role = normalizedRole === "manager" ? "manager" : normalizedRole === "collaborator" ? "collaborator" : null return { email, name, role, } } export async function GET(request: NextRequest) { const session = await assertAuthenticatedSession() if (!session || session.user?.role !== "machine") { return NextResponse.json({ error: "Sessão de máquina não encontrada." }, { status: 403 }) } const convexUrl = env.NEXT_PUBLIC_CONVEX_URL if (!convexUrl) { return NextResponse.json({ error: "Convex não configurado." }, { status: 500 }) } const client = new ConvexHttpClient(convexUrl) const cookieStore = await cookies() const cookieValue = cookieStore.get(MACHINE_CTX_COOKIE)?.value ?? null const decoded = cookieValue ? decodeMachineCookie(cookieValue) : null let machineId: Id<"machines"> | null = decoded?.machineId ? (decoded.machineId as Id<"machines">) : null if (!machineId) { try { const lookup = (await client.query(api.machines.findByAuthEmail, { authEmail: session.user.email.toLowerCase(), })) as { id: string } | null if (!lookup?.id) { return NextResponse.json({ error: "Máquina não vinculada à sessão atual." }, { status: 404 }) } machineId = lookup.id as Id<"machines"> } catch (error) { console.error("[machines.session] Falha ao localizar máquina por e-mail", error) return NextResponse.json({ error: "Não foi possível localizar a máquina." }, { status: 500 }) } } try { let context = (await client.query(api.machines.getContext, { machineId, })) as { id: string tenantId: string companyId: string | null companySlug: string | null persona: string | null assignedUserId: string | null assignedUserEmail: string | null assignedUserName: string | null assignedUserRole: string | null metadata: Record | null authEmail: string | null } const metadataCollaborator = extractCollaboratorFromMetadata(context.metadata) let ensuredAssignedUserId = context.assignedUserId let ensuredAssignedUserEmail = context.assignedUserEmail ?? metadataCollaborator?.email ?? null let ensuredAssignedUserName = context.assignedUserName ?? metadataCollaborator?.name ?? null let ensuredAssignedUserRole = context.assignedUserRole ?? (metadataCollaborator?.role ? metadataCollaborator.role.toUpperCase() : null) let ensuredPersona = context.persona ?? metadataCollaborator?.role ?? null if (!ensuredAssignedUserId && ensuredAssignedUserEmail) { try { const personaRoleCandidate = ensuredPersona ?? ensuredAssignedUserRole ?? "collaborator" const personaRole = personaRoleCandidate.toString().toLowerCase() const normalizedPersona = personaRole === "manager" ? "manager" : "collaborator" const assignedRole = normalizedPersona === "manager" ? "MANAGER" : "COLLABORATOR" const ensuredUser = (await client.mutation(api.users.ensureUser, { tenantId: context.tenantId ?? DEFAULT_TENANT_ID, email: ensuredAssignedUserEmail, name: ensuredAssignedUserName ?? ensuredAssignedUserEmail, role: normalizedPersona.toUpperCase(), companyId: context.companyId ? (context.companyId as Id<"companies">) : undefined, })) as { _id?: Id<"users"> name?: string | null role?: string | null } | null if (ensuredUser?._id) { ensuredAssignedUserId = ensuredUser._id as string ensuredAssignedUserName = ensuredUser.name ?? ensuredAssignedUserName ?? ensuredAssignedUserEmail ensuredAssignedUserRole = ensuredUser.role ?? ensuredAssignedUserRole ?? assignedRole ensuredPersona = normalizedPersona await client.mutation(api.machines.updatePersona, { machineId: machineId as Id<"machines">, persona: normalizedPersona, assignedUserId: ensuredUser._id as Id<"users">, assignedUserEmail: ensuredAssignedUserEmail, assignedUserName: ensuredAssignedUserName ?? undefined, assignedUserRole: (ensuredAssignedUserRole ?? assignedRole).toUpperCase(), }) context = (await client.query(api.machines.getContext, { machineId, })) as typeof context ensuredAssignedUserId = context.assignedUserId ?? ensuredAssignedUserId ensuredAssignedUserEmail = context.assignedUserEmail ?? ensuredAssignedUserEmail ensuredAssignedUserName = context.assignedUserName ?? ensuredAssignedUserName ensuredAssignedUserRole = context.assignedUserRole ?? ensuredAssignedUserRole ensuredPersona = context.persona ?? ensuredPersona } } catch (error) { console.error("[machines.session] Falha ao garantir usuário vinculado", error) } } const resolvedPersona = context.persona ?? ensuredPersona ?? (ensuredAssignedUserRole ? ensuredAssignedUserRole.toLowerCase() : null) const responsePayload = { machineId: context.id, persona: resolvedPersona, assignedUserId: ensuredAssignedUserId, assignedUserEmail: ensuredAssignedUserEmail, assignedUserName: ensuredAssignedUserName, assignedUserRole: ensuredAssignedUserRole, } const response = NextResponse.json({ machine: { ...context, persona: resolvedPersona, assignedUserEmail: ensuredAssignedUserEmail ?? null, assignedUserId: ensuredAssignedUserId ?? null, assignedUserName: ensuredAssignedUserName ?? null, assignedUserRole: ensuredAssignedUserRole ?? null, }, cookie: responsePayload, }) const isSecure = request.nextUrl.protocol === "https:" response.cookies.set({ name: MACHINE_CTX_COOKIE, value: encodeMachineCookie(responsePayload), httpOnly: true, sameSite: "lax", secure: isSecure, path: "/", maxAge: 60 * 60 * 24 * 30, }) return response } catch (error) { console.error("[machines.session] Falha ao obter contexto da máquina", error) return NextResponse.json({ error: "Falha ao obter contexto da máquina." }, { status: 500 }) } }