import { db } from '@/lib/db'; import { scriptCollections, collectionScripts } from '@/lib/db/schema'; import { eq, and, desc } from 'drizzle-orm'; import { generateId, ApiError } from './index'; export interface CreateCollectionData { name: string; description?: string; authorId: string; isPublic?: boolean; } export interface UpdateCollectionData { name?: string; description?: string; isPublic?: boolean; } // Create a new collection export async function createCollection(data: CreateCollectionData) { try { const collectionId = generateId(); const now = new Date(); await db.insert(scriptCollections).values({ id: collectionId, name: data.name, description: data.description, authorId: data.authorId, isPublic: data.isPublic ?? true, createdAt: now, updatedAt: now, }); const collection = { id: collectionId, name: data.name, description: data.description, authorId: data.authorId, isPublic: data.isPublic ?? true, createdAt: now, updatedAt: now, }; return collection; } catch (error) { throw new ApiError(`Failed to create collection: ${error}`, 500); } } // Get collection by ID export async function getCollectionById(id: string) { try { const collection = await db.query.scriptCollections.findFirst({ where: eq(scriptCollections.id, id), with: { author: { columns: { id: true, username: true, displayName: true, avatarUrl: true, }, }, scripts: { with: { script: { with: { author: { columns: { id: true, username: true, displayName: true, avatarUrl: true, }, }, }, }, }, orderBy: desc(collectionScripts.addedAt), }, }, }); if (!collection) { throw new ApiError('Collection not found', 404); } return collection; } catch (error) { if (error instanceof ApiError) throw error; throw new ApiError(`Failed to get collection: ${error}`, 500); } } // Get collections by user export async function getUserCollections(userId: string) { try { const collections = await db.query.scriptCollections.findMany({ where: eq(scriptCollections.authorId, userId), with: { scripts: { with: { script: true, }, }, }, orderBy: desc(scriptCollections.createdAt), }); return collections; } catch (error) { throw new ApiError(`Failed to get user collections: ${error}`, 500); } } // Get public collections export async function getPublicCollections(limit: number = 20, offset: number = 0) { try { const collections = await db.query.scriptCollections.findMany({ where: eq(scriptCollections.isPublic, true), with: { author: { columns: { id: true, username: true, displayName: true, avatarUrl: true, }, }, scripts: { with: { script: true, }, limit: 5, // Preview of scripts in collection }, }, orderBy: desc(scriptCollections.createdAt), limit, offset, }); return collections; } catch (error) { throw new ApiError(`Failed to get public collections: ${error}`, 500); } } // Update collection export async function updateCollection(id: string, data: UpdateCollectionData, userId: string) { try { // Check if user owns the collection const collection = await getCollectionById(id); if (collection.authorId !== userId) { throw new ApiError('Unauthorized to update this collection', 403); } const updateData = { ...data, updatedAt: new Date(), }; await db .update(scriptCollections) .set(updateData) .where(eq(scriptCollections.id, id)); const updatedCollection = { ...collection, ...updateData }; return updatedCollection; } catch (error) { if (error instanceof ApiError) throw error; throw new ApiError(`Failed to update collection: ${error}`, 500); } } // Delete collection export async function deleteCollection(id: string, userId: string) { try { const collection = await getCollectionById(id); if (collection.authorId !== userId) { throw new ApiError('Unauthorized to delete this collection', 403); } // Delete all scripts in collection first await db.delete(collectionScripts).where(eq(collectionScripts.collectionId, id)); // Delete the collection await db.delete(scriptCollections).where(eq(scriptCollections.id, id)); return { success: true }; } catch (error) { if (error instanceof ApiError) throw error; throw new ApiError(`Failed to delete collection: ${error}`, 500); } } // Add script to collection export async function addScriptToCollection(collectionId: string, scriptId: string, userId: string) { try { // Check if user owns the collection const collection = await getCollectionById(collectionId); if (collection.authorId !== userId) { throw new ApiError('Unauthorized to modify this collection', 403); } // Check if script is already in collection const existing = await db.query.collectionScripts.findFirst({ where: and( eq(collectionScripts.collectionId, collectionId), eq(collectionScripts.scriptId, scriptId) ), }); if (existing) { throw new ApiError('Script is already in this collection', 400); } const collectionScriptData = { id: generateId(), collectionId, scriptId, addedAt: new Date(), }; await db.insert(collectionScripts).values(collectionScriptData); return collectionScriptData; } catch (error) { if (error instanceof ApiError) throw error; throw new ApiError(`Failed to add script to collection: ${error}`, 500); } } // Remove script from collection export async function removeScriptFromCollection(collectionId: string, scriptId: string, userId: string) { try { // Check if user owns the collection const collection = await getCollectionById(collectionId); if (collection.authorId !== userId) { throw new ApiError('Unauthorized to modify this collection', 403); } await db .delete(collectionScripts) .where( and( eq(collectionScripts.collectionId, collectionId), eq(collectionScripts.scriptId, scriptId) ) ); return { success: true }; } catch (error) { if (error instanceof ApiError) throw error; throw new ApiError(`Failed to remove script from collection: ${error}`, 500); } } // Check if script is in collection export async function isScriptInCollection(collectionId: string, scriptId: string) { try { const collectionScript = await db.query.collectionScripts.findFirst({ where: and( eq(collectionScripts.collectionId, collectionId), eq(collectionScripts.scriptId, scriptId) ), }); return !!collectionScript; } catch (error) { throw new ApiError(`Failed to check if script is in collection: ${error}`, 500); } }