import { NextResponse } from "next/server" import { ZodError } from "zod" import { Prisma } from "@prisma/client" import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library" import { prisma } from "@/lib/prisma" import { assertStaffSession } from "@/lib/auth-server" import { isAdmin } from "@/lib/authz" import { removeConvexCompany, syncConvexCompany } from "@/server/companies-sync" import { buildCompanyData, fetchCompanyById, formatZodError, normalizeCompany, sanitizeCompanyInput, } from "@/server/company-service" import type { CompanyFormValues } from "@/lib/schemas/company" export const runtime = "nodejs" function mergePayload(base: CompanyFormValues, updates: Record): Record { const merged: Record = { ...base, ...updates } if (!("businessHours" in updates)) merged.businessHours = base.businessHours if (!("communicationChannels" in updates)) merged.communicationChannels = base.communicationChannels if (!("clientDomains" in updates)) merged.clientDomains = base.clientDomains if (!("fiscalAddress" in updates)) merged.fiscalAddress = base.fiscalAddress if (!("regulatedEnvironments" in updates)) merged.regulatedEnvironments = base.regulatedEnvironments if (!("contacts" in updates)) merged.contacts = base.contacts if (!("locations" in updates)) merged.locations = base.locations if (!("contracts" in updates)) merged.contracts = base.contracts if (!("sla" in updates)) merged.sla = base.sla if (!("tags" in updates)) merged.tags = base.tags if (!("customFields" in updates)) merged.customFields = base.customFields if ("privacyPolicy" in updates) { const incoming = updates.privacyPolicy if (incoming && typeof incoming === "object") { merged.privacyPolicy = { ...base.privacyPolicy, ...incoming, } } } else { merged.privacyPolicy = base.privacyPolicy } merged.tenantId = base.tenantId return merged } export async function PATCH( request: Request, { params }: { params: Promise<{ id: string }> } ) { 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 editar empresas" }, { status: 403 }) } const { id } = await params try { const existing = await fetchCompanyById(id) if (!existing) { return NextResponse.json({ error: "Empresa não encontrada" }, { status: 404 }) } if (existing.tenantId !== (session.user.tenantId ?? existing.tenantId)) { return NextResponse.json({ error: "Acesso negado" }, { status: 403 }) } const rawBody = (await request.json()) as Record const normalized = normalizeCompany(existing) const { id: _ignoreId, provisioningCode: _ignoreCode, createdAt: _createdAt, updatedAt: _updatedAt, ...baseForm } = normalized void _ignoreId void _ignoreCode void _createdAt void _updatedAt const mergedInput = mergePayload(baseForm, rawBody) const form = sanitizeCompanyInput(mergedInput, existing.tenantId) const createData = buildCompanyData(form, existing.tenantId) const { tenantId: _omitTenant, ...updateData } = createData void _omitTenant const company = await prisma.company.update({ where: { id }, data: updateData, }) if (company.provisioningCode) { const synced = await syncConvexCompany({ tenantId: company.tenantId, slug: company.slug, name: company.name, provisioningCode: company.provisioningCode, }) if (!synced) { console.warn("[admin.companies] Convex não configurado; atualização aplicada apenas no Prisma.") } } return NextResponse.json({ company: normalizeCompany(company) }) } catch (error) { if (error instanceof ZodError) { return NextResponse.json({ error: "Dados inválidos", issues: formatZodError(error) }, { status: 422 }) } if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") { return NextResponse.json({ error: "Já existe uma empresa com este slug." }, { status: 409 }) } console.error("Failed to update company", error) return NextResponse.json({ error: "Falha ao atualizar empresa" }, { status: 500 }) } } export async function DELETE( _: Request, { params }: { params: Promise<{ id: string }> } ) { 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 excluir empresas" }, { status: 403 }) } const { id } = await params const company = await fetchCompanyById(id) if (!company) { return NextResponse.json({ error: "Empresa não encontrada" }, { status: 404 }) } if (company.tenantId !== (session.user.tenantId ?? company.tenantId)) { return NextResponse.json({ error: "Acesso negado" }, { status: 403 }) } try { const result = await prisma.$transaction(async (tx: Prisma.TransactionClient) => { const users = await tx.user.updateMany({ where: { companyId: company.id, tenantId: company.tenantId }, data: { companyId: null }, }) const tickets = await tx.ticket.updateMany({ where: { companyId: company.id, tenantId: company.tenantId }, data: { companyId: null }, }) await tx.company.delete({ where: { id: company.id } }) return { detachedUsers: users.count, detachedTickets: tickets.count } }) if (company.slug) { const removed = await removeConvexCompany({ tenantId: company.tenantId, slug: company.slug, }) if (!removed) { console.warn("[admin.companies] Convex não configurado; empresa removida apenas no Prisma.") } } return NextResponse.json({ ok: true, ...result }) } catch (error) { if (error instanceof PrismaClientKnownRequestError && error.code === "P2003") { return NextResponse.json( { error: "Não é possível remover esta empresa pois existem registros vinculados." }, { status: 409 } ) } console.error("Failed to delete company", error) return NextResponse.json({ error: "Falha ao excluir empresa" }, { status: 500 }) } }