import { NextResponse } from "next/server"; import { prisma } from "@/lib/db"; import { getActiveAccountId } from "@/lib/account-context"; import { apiRouteErrorResponse } from "@/lib/auth/api"; import { isAccountInUserScope, requireUserAccountScope } from "@/lib/auth/user-scope"; import { migrateOrphanProductContexts, syncProfileContextToTopics, validateProfileContext, } from "@/lib/services/product-profile"; export async function GET() { try { const accountId = await getActiveAccountId(); const { where, accountIds } = await requireUserAccountScope(accountId); try { await migrateOrphanProductContexts(accountIds); } catch (migrateErr) { console.error("[product-profiles] migrate failed:", migrateErr); } const profiles = await prisma.productProfile.findMany({ where, orderBy: { updatedAt: "desc" }, }); return NextResponse.json({ profiles }); } catch (error) { return apiRouteErrorResponse(error, "product-profiles"); } } export async function POST(request: Request) { try { const { label, context } = (await request.json()) as { label?: string; context?: string; }; if (!label?.trim()) { return NextResponse.json({ error: "請填寫名稱" }, { status: 400 }); } const serialized = context?.trim() || ""; if (!validateProfileContext(serialized)) { return NextResponse.json({ error: "請填寫品牌、產品或特色" }, { status: 400 }); } const accountId = await getActiveAccountId(); if (!accountId) { return NextResponse.json({ error: "請先建立並選定經營帳號" }, { status: 400 }); } const profile = await prisma.productProfile.create({ data: { accountId, label: label.trim(), context: serialized, }, }); return NextResponse.json({ profile }); } catch (error) { return apiRouteErrorResponse(error, "product-profiles/create"); } } export async function PATCH(request: Request) { try { const { id, label, context } = (await request.json()) as { id?: string; label?: string; context?: string; }; if (!id) { return NextResponse.json({ error: "缺少 id" }, { status: 400 }); } const { accountIds } = await requireUserAccountScope(await getActiveAccountId()); const existing = await prisma.productProfile.findUnique({ where: { id } }); if (!existing || !isAccountInUserScope(accountIds, existing.accountId)) { return NextResponse.json({ error: "找不到品牌與產品" }, { status: 404 }); } const nextContext = context !== undefined ? context.trim() : existing.context; if (context !== undefined && !validateProfileContext(nextContext)) { return NextResponse.json({ error: "請填寫品牌、產品或特色" }, { status: 400 }); } const profile = await prisma.productProfile.update({ where: { id }, data: { ...(label !== undefined && { label: label.trim() }), ...(context !== undefined && { context: nextContext }), }, }); if (context !== undefined) { await syncProfileContextToTopics(id, nextContext); } return NextResponse.json({ profile }); } catch (error) { return apiRouteErrorResponse(error, "product-profiles/update"); } } export async function DELETE(request: Request) { try { const { searchParams } = new URL(request.url); const id = searchParams.get("id"); if (!id) { return NextResponse.json({ error: "缺少 id" }, { status: 400 }); } const { accountIds } = await requireUserAccountScope(await getActiveAccountId()); const existing = await prisma.productProfile.findUnique({ where: { id } }); if (!existing || !isAccountInUserScope(accountIds, existing.accountId)) { return NextResponse.json({ error: "找不到品牌與產品" }, { status: 404 }); } const linked = await prisma.topic.count({ where: { productProfileId: id } }); if (linked > 0) { return NextResponse.json( { error: `仍有 ${linked} 個主題使用此品牌,請先更換或刪除主題` }, { status: 400 } ); } await prisma.productProfile.delete({ where: { id } }); return NextResponse.json({ success: true }); } catch (error) { return apiRouteErrorResponse(error, "product-profiles/delete"); } }