"use server"; import { revalidatePath } from "next/cache"; import { rawDb, uniqueSlug } from "@/lib/db/client"; const EXCLUSIVE_GROUPS: string[][] = [["favorite", "vip"]]; function getExclusivePeers(categoryId: number): number[] { const cat = rawDb.prepare(`SELECT slug FROM actress_categories WHERE id = ?`).get(categoryId) as { slug: string } | undefined; if (!cat) return []; const group = EXCLUSIVE_GROUPS.find((g) => g.includes(cat.slug)); if (!group) return []; const peers = group.filter((s) => s !== cat.slug); if (peers.length === 0) return []; const placeholders = peers.map(() => "?").join(","); const rows = rawDb.prepare(`SELECT id FROM actress_categories WHERE slug IN (${placeholders})`).all(...peers) as Array<{ id: number }>; return rows.map((r) => r.id); } export async function toggleActressCategory(actressId: number, categoryId: number) { const exists = rawDb.prepare(` SELECT 1 FROM actress_categories_map WHERE actress_id = ? AND category_id = ? `).get(actressId, categoryId); if (exists) { rawDb.prepare(`DELETE FROM actress_categories_map WHERE actress_id = ? AND category_id = ?`).run(actressId, categoryId); } else { // Adding: also remove any peer category in an exclusive group. const peers = getExclusivePeers(categoryId); const tx = rawDb.transaction(() => { if (peers.length > 0) { const placeholders = peers.map(() => "?").join(","); rawDb.prepare(` DELETE FROM actress_categories_map WHERE actress_id = ? AND category_id IN (${placeholders}) `).run(actressId, ...peers); } rawDb.prepare(`INSERT INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`).run(actressId, categoryId); }); tx(); } const a = rawDb.prepare(`SELECT slug FROM actresses WHERE id = ?`).get(actressId) as { slug: string } | undefined; revalidatePath("/actress"); if (a) revalidatePath(`/actress/${a.slug}`); return { added: !exists }; } export async function setActressCategories(actressId: number, categoryIds: number[]) { const tx = rawDb.transaction(() => { rawDb.prepare(`DELETE FROM actress_categories_map WHERE actress_id = ?`).run(actressId); const ins = rawDb.prepare(`INSERT INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`); for (const id of categoryIds) ins.run(actressId, id); }); tx(); const a = rawDb.prepare(`SELECT slug FROM actresses WHERE id = ?`).get(actressId) as { slug: string } | undefined; revalidatePath("/actress"); if (a) revalidatePath(`/actress/${a.slug}`); } export async function createActressCategory(input: { name: string; color?: string | null; icon?: string | null; priority?: number }) { const trimmed = input.name.trim(); if (!trimmed) return null; const existing = rawDb.prepare(`SELECT id, slug FROM actress_categories WHERE name = ?`).get(trimmed) as { id: number; slug: string } | undefined; if (existing) return existing; const slug = uniqueSlug(rawDb, "actress_categories", trimmed); const row = rawDb.prepare(` INSERT INTO actress_categories (name, slug, color, icon, priority, builtin) VALUES (?, ?, ?, ?, ?, 0) RETURNING id `).get(trimmed, slug, input.color ?? null, input.icon ?? null, input.priority ?? 50) as { id: number }; revalidatePath("/actress"); return { id: row.id, slug }; } export async function bulkAddCategory(actressIds: number[], categoryId: number) { if (actressIds.length === 0) return; const peers = getExclusivePeers(categoryId); const ins = rawDb.prepare(`INSERT OR IGNORE INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`); const tx = rawDb.transaction(() => { if (peers.length > 0) { const peerPh = peers.map(() => "?").join(","); const idPh = actressIds.map(() => "?").join(","); rawDb.prepare(` DELETE FROM actress_categories_map WHERE actress_id IN (${idPh}) AND category_id IN (${peerPh}) `).run(...actressIds, ...peers); } for (const id of actressIds) ins.run(id, categoryId); }); tx(); revalidatePath("/actress"); } export async function bulkRemoveCategory(actressIds: number[], categoryId: number) { if (actressIds.length === 0) return; const placeholders = actressIds.map(() => "?").join(","); rawDb.prepare(` DELETE FROM actress_categories_map WHERE category_id = ? AND actress_id IN (${placeholders}) `).run(categoryId, ...actressIds); revalidatePath("/actress"); } export async function deleteActressCategory(categoryId: number) { const row = rawDb.prepare(`SELECT builtin FROM actress_categories WHERE id = ?`).get(categoryId) as { builtin: number } | undefined; if (!row) return { ok: false, reason: "not found" }; if (row.builtin) return { ok: false, reason: "built-in category cannot be deleted" }; rawDb.prepare(`DELETE FROM actress_categories WHERE id = ?`).run(categoryId); revalidatePath("/actress"); return { ok: true }; }