import { NextResponse } from "next/server" import { randomBytes } from "crypto" import { hashPassword } from "better-auth/crypto" import { ConvexHttpClient } from "convex/browser" import type { UserRole } from "@prisma/client" import { api } from "@/convex/_generated/api" import { prisma } from "@/lib/prisma" import { DEFAULT_TENANT_ID } from "@/lib/constants" import { assertStaffSession } from "@/lib/auth-server" import { ROLE_OPTIONS, type RoleOption, isAdmin } from "@/lib/authz" export const runtime = "nodejs" function normalizeRole(input: string | null | undefined): RoleOption { const role = (input ?? "agent").toLowerCase() as RoleOption return (ROLE_OPTIONS as readonly string[]).includes(role) ? role : "agent" } const USER_ROLE_OPTIONS: ReadonlyArray = ["ADMIN", "MANAGER", "AGENT", "COLLABORATOR"] function mapToUserRole(role: RoleOption): UserRole { const candidate = role.toUpperCase() as UserRole return USER_ROLE_OPTIONS.includes(candidate) ? candidate : "AGENT" } function generatePassword(length = 12) { const bytes = randomBytes(length) return Array.from(bytes) .map((byte) => (byte % 36).toString(36)) .join("") } export async function GET() { const session = await assertStaffSession() if (!session) { return NextResponse.json({ error: "Não autorizado" }, { status: 401 }) } const users = await prisma.authUser.findMany({ orderBy: { createdAt: "desc" }, select: { id: true, email: true, name: true, role: true, tenantId: true, createdAt: true, updatedAt: true, }, }) return NextResponse.json({ users }) } export async function POST(request: Request) { const session = await assertStaffSession() if (!session) { return NextResponse.json({ error: "Não autorizado" }, { status: 401 }) } if (!isAdmin(session.user.role)) { return NextResponse.json({ error: "Apenas administradores podem criar usuários" }, { status: 403 }) } const payload = await request.json().catch(() => null) if (!payload || typeof payload !== "object") { return NextResponse.json({ error: "Payload inválido" }, { status: 400 }) } const emailInput = typeof payload.email === "string" ? payload.email.trim().toLowerCase() : "" const nameInput = typeof payload.name === "string" ? payload.name.trim() : "" const roleInput = typeof payload.role === "string" ? payload.role : undefined const tenantInput = typeof payload.tenantId === "string" ? payload.tenantId.trim() : undefined if (!emailInput || !emailInput.includes("@")) { return NextResponse.json({ error: "Informe um e-mail válido" }, { status: 400 }) } const role = normalizeRole(roleInput) const tenantId = tenantInput || session.user.tenantId || DEFAULT_TENANT_ID const userRole = mapToUserRole(role) const existing = await prisma.authUser.findUnique({ where: { email: emailInput } }) if (existing) { return NextResponse.json({ error: "Já existe um usuário com este e-mail" }, { status: 409 }) } const password = generatePassword() const hashedPassword = await hashPassword(password) const user = await prisma.authUser.create({ data: { email: emailInput, name: nameInput || emailInput, role, tenantId, accounts: { create: { providerId: "credential", accountId: emailInput, password: hashedPassword, }, }, }, select: { id: true, email: true, name: true, role: true, tenantId: true, createdAt: true, }, }) await prisma.user.upsert({ where: { email: user.email }, update: { name: user.name ?? user.email, role: userRole, tenantId, }, create: { email: user.email, name: user.name ?? user.email, role: userRole, tenantId, }, }) const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL if (convexUrl) { try { const convex = new ConvexHttpClient(convexUrl) await convex.mutation(api.users.ensureUser, { tenantId, email: emailInput, name: nameInput || emailInput, avatarUrl: undefined, role: userRole, }) } catch (error) { console.warn("Falha ao sincronizar usuário no Convex", error) } } return NextResponse.json({ user, temporaryPassword: password }) }