import { type NextRequest, NextResponse } from "next/server"; import { requireAdminUser } from "@/lib/auth/middleware"; import { insertCategoryItem, listCategoryTemplates, updateCategoryItem, } from "@/lib/items/sqlite-manager"; import { createAdminItem, getItemById, searchAdminItems, updateAdminItem, } from "@/lib/prisma/queries/items"; function parseNumber( value: string | null | undefined, fallback: number, ): number { const parsed = Number(value); return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; } function parseList(value: unknown): string[] { if (Array.isArray(value)) { return value .map((entry) => (typeof entry === "string" ? entry.trim() : "")) .filter(Boolean); } if (typeof value === "string") { return value .split(",") .map((entry) => entry.trim()) .filter(Boolean); } return []; } function normalizeDynamicFields( category: string, rawFields: Record | undefined, ) { if (!rawFields || typeof rawFields !== "object") { return {} as Record; } const templates = listCategoryTemplates(); const template = templates.find( (entry) => entry.name === category.toLowerCase(), ); if (!template) { return rawFields; } const columnMap = new Map( template.columns.map((column) => [column.name, column]), ); const normalized: Record = {}; for (const [key, value] of Object.entries(rawFields)) { if (["id", "nome", "image_url", "image_local_path"].includes(key)) { continue; } const column = columnMap.get(key); if (!column) { continue; } if (value === "" || value === null || value === undefined) { normalized[key] = null; continue; } switch (column.type) { case "INTEGER": case "BOOLEAN": { const parsed = Number(value); normalized[key] = Number.isFinite(parsed) ? parsed : null; break; } case "REAL": { const parsed = Number(value); normalized[key] = Number.isFinite(parsed) ? parsed : null; break; } default: normalized[key] = String(value); } } return normalized; } export async function GET(request: NextRequest) { const auth = await requireAdminUser(request); if (auth instanceof NextResponse) { return auth; } const { searchParams } = new URL(request.url); const page = parseNumber(searchParams.get("page"), 1); const pageSize = Math.min(parseNumber(searchParams.get("pageSize"), 50), 200); const q = searchParams.get("q") || undefined; const category = searchParams.get("category") || undefined; const rarity = searchParams.get("rarity") || undefined; const server = searchParams.get("server") || undefined; try { const result = await searchAdminItems({ q, category, rarity, server, page, pageSize, }); return NextResponse.json(result, { status: 200 }); } catch (error: any) { console.error("[admin/items][GET] erro", error?.message); return NextResponse.json( { success: false, error: "Falha ao consultar itens", message: error?.message || "Erro desconhecido", }, { status: 500 }, ); } } export async function POST(request: NextRequest) { const auth = await requireAdminUser(request); if (auth instanceof NextResponse) { return auth; } try { const body = await request.json(); const name = typeof body?.name === "string" ? body.name.trim() : ""; const category = typeof body?.category === "string" ? body.category.trim().toLowerCase() : ""; const originServer = typeof body?.server === "string" ? body.server.trim() || null : null; if (!name || !category) { return NextResponse.json( { success: false, error: "Nome e categoria são obrigatórios." }, { status: 400 }, ); } const dynamicFields = normalizeDynamicFields(category, body?.fields); const imageUrl = typeof body?.imageUrl === "string" ? body.imageUrl.trim() || null : null; const imageLocalPath = typeof body?.imageLocalPath === "string" ? body.imageLocalPath.trim() || null : null; const sqliteData = { nome: name, image_url: imageUrl, image_local_path: imageLocalPath, ...dynamicFields, } as Record; // Se enviado servidor de origem, inclui na linha do SQLite e garante presença na lista de servidores do item if (originServer) { sqliteData.server = originServer; } const sqliteId = insertCategoryItem({ category, data: sqliteData }); const metadataBase = typeof body?.metadata === "object" && body.metadata !== null ? body.metadata : {}; const metadata = { ...metadataBase, ...dynamicFields } as Record< string, unknown >; const itemServers = parseList(body?.servers); const finalServers = originServer ? Array.from(new Set([originServer, ...itemServers])) : itemServers; const item = await createAdminItem({ item_name: name, category, rarity: typeof body?.rarity === "string" ? body.rarity.trim() || null : null, image_url: imageUrl, image_local_path: imageLocalPath, level: typeof body?.level === "number" ? body.level : null, weight: typeof body?.weight === "number" ? body.weight : null, slots: typeof body?.slots === "number" ? body.slots : null, skill: typeof body?.skill === "string" ? body.skill.trim() || null : null, servers: finalServers, tags: parseList(body?.tags), description: typeof body?.description === "string" ? body.description.trim() || null : null, metadata, source_table_name: category, source_table_id: sqliteId, }); return NextResponse.json( { success: true, item, }, { status: 201 }, ); } catch (error: any) { console.error("[admin/items][POST] erro", error?.message); return NextResponse.json( { success: false, error: "Falha ao criar item", message: error?.message || "Erro desconhecido", }, { status: 500 }, ); } } export async function PUT(request: NextRequest) { const auth = await requireAdminUser(request); if (auth instanceof NextResponse) { return auth; } try { const body = await request.json(); const id = Number(body?.id); if (!Number.isFinite(id) || id <= 0) { return NextResponse.json( { success: false, error: "ID inválido." }, { status: 400 }, ); } const existing = await getItemById(id); if (!existing) { return NextResponse.json( { success: false, error: "Item não encontrado." }, { status: 404 }, ); } const category = (typeof body?.category === "string" ? body.category.trim().toLowerCase() : existing.category) ?? existing.category; if (category !== existing.category) { return NextResponse.json( { success: false, error: "Alterar a categoria de um item não é suportado.", }, { status: 400 }, ); } const dynamicFields = normalizeDynamicFields(category, body?.fields); const imageUrl = typeof body?.imageUrl === "string" ? body.imageUrl.trim() : undefined; const imageLocalPath = typeof body?.imageLocalPath === "string" ? body.imageLocalPath.trim() : undefined; if (existing.source_table_id && existing.source_table_name) { const sqliteData: Record = { nome: typeof body?.name === "string" ? body.name.trim() : existing.item_name, }; if (imageUrl !== undefined) sqliteData.image_url = imageUrl; else sqliteData.image_url = existing.image_url; if (imageLocalPath !== undefined) sqliteData.image_local_path = imageLocalPath; else sqliteData.image_local_path = existing.image_local_path; for (const [key, value] of Object.entries(dynamicFields)) { sqliteData[key] = value; } updateCategoryItem( existing.source_table_name, existing.source_table_id, sqliteData, ); } const metadataBase = typeof body?.metadata === "object" && body.metadata !== null ? body.metadata : existing.metadata; const metadata = { ...metadataBase, ...dynamicFields } as Record< string, unknown >; const item = await updateAdminItem(id, { item_name: typeof body?.name === "string" ? body.name.trim() : undefined, category, rarity: typeof body?.rarity === "string" ? body.rarity.trim() : undefined, image_url: imageUrl, image_local_path: imageLocalPath, level: typeof body?.level === "number" ? body.level : undefined, weight: typeof body?.weight === "number" ? body.weight : undefined, slots: typeof body?.slots === "number" ? body.slots : undefined, skill: typeof body?.skill === "string" ? body.skill.trim() : undefined, servers: parseList(body?.servers), tags: parseList(body?.tags), description: typeof body?.description === "string" ? body.description.trim() : body?.description === null ? null : undefined, metadata, }); return NextResponse.json( { success: true, item, }, { status: 200 }, ); } catch (error: any) { console.error("[admin/items][PUT] erro", error?.message); return NextResponse.json( { success: false, error: "Falha ao atualizar item", message: error?.message || "Erro desconhecido", }, { status: 500 }, ); } }