import { db } from '@/lib/db'; import { scriptAnalytics, scripts } from '@/lib/db/schema'; import { eq, and, gte, lte, desc, count, sql } from 'drizzle-orm'; import { generateId, ApiError } from './index'; export interface TrackEventData { scriptId: string; eventType: 'view' | 'download' | 'share'; userId?: string; userAgent?: string; ipAddress?: string; referrer?: string; } export interface AnalyticsFilters { scriptId?: string; eventType?: string; startDate?: Date; endDate?: Date; userId?: string; } // Track an analytics event export async function trackEvent(data: TrackEventData) { try { await db.insert(scriptAnalytics).values({ id: generateId(), scriptId: data.scriptId, eventType: data.eventType, userId: data.userId, userAgent: data.userAgent, ipAddress: data.ipAddress, referrer: data.referrer, createdAt: new Date(), }); // Update script counters based on event type if (data.eventType === 'view') { await db .update(scripts) .set({ viewCount: sql`${scripts.viewCount} + 1`, }) .where(eq(scripts.id, data.scriptId)); } else if (data.eventType === 'download') { await db .update(scripts) .set({ downloadCount: sql`${scripts.downloadCount} + 1`, }) .where(eq(scripts.id, data.scriptId)); } return { success: true }; } catch (error) { throw new ApiError(`Failed to track event: ${error}`, 500); } } // Get analytics events with filters export async function getAnalyticsEvents(filters: AnalyticsFilters = {}) { try { let query = db.select().from(scriptAnalytics); let conditions: any[] = []; if (filters.scriptId) { conditions.push(eq(scriptAnalytics.scriptId, filters.scriptId)); } if (filters.eventType) { conditions.push(eq(scriptAnalytics.eventType, filters.eventType)); } if (filters.userId) { conditions.push(eq(scriptAnalytics.userId, filters.userId)); } if (filters.startDate) { conditions.push(gte(scriptAnalytics.createdAt, filters.startDate)); } if (filters.endDate) { conditions.push(lte(scriptAnalytics.createdAt, filters.endDate)); } if (conditions.length > 0) { query = query.where(and(...conditions)) as any; } const events = await query.orderBy(desc(scriptAnalytics.createdAt)); return events; } catch (error) { throw new ApiError(`Failed to get analytics events: ${error}`, 500); } } // Get analytics summary for a script export async function getScriptAnalytics(scriptId: string, days: number = 30) { try { const startDate = new Date(); startDate.setDate(startDate.getDate() - days); // Get event counts by type const eventCounts = await db .select({ eventType: scriptAnalytics.eventType, count: count(scriptAnalytics.id), }) .from(scriptAnalytics) .where( and( eq(scriptAnalytics.scriptId, scriptId), gte(scriptAnalytics.createdAt, startDate) ) ) .groupBy(scriptAnalytics.eventType); // Get daily activity const dailyActivity = await db .select({ date: sql`DATE(${scriptAnalytics.createdAt})`, eventType: scriptAnalytics.eventType, count: count(scriptAnalytics.id), }) .from(scriptAnalytics) .where( and( eq(scriptAnalytics.scriptId, scriptId), gte(scriptAnalytics.createdAt, startDate) ) ) .groupBy(sql`DATE(${scriptAnalytics.createdAt})`, scriptAnalytics.eventType); // Get referrer statistics const referrers = await db .select({ referrer: scriptAnalytics.referrer, count: count(scriptAnalytics.id), }) .from(scriptAnalytics) .where( and( eq(scriptAnalytics.scriptId, scriptId), gte(scriptAnalytics.createdAt, startDate) ) ) .groupBy(scriptAnalytics.referrer) .orderBy(desc(count(scriptAnalytics.id))) .limit(10); return { eventCounts, dailyActivity, referrers, periodDays: days, }; } catch (error) { throw new ApiError(`Failed to get script analytics: ${error}`, 500); } } // Get platform-wide analytics (admin only) export async function getPlatformAnalytics(days: number = 30) { try { const startDate = new Date(); startDate.setDate(startDate.getDate() - days); // Total scripts and activity const [totals] = await db .select({ totalScripts: count(scripts.id), approvedScripts: sql`SUM(CASE WHEN ${scripts.isApproved} = 1 THEN 1 ELSE 0 END)`, pendingScripts: sql`SUM(CASE WHEN ${scripts.isApproved} = 0 THEN 1 ELSE 0 END)`, }) .from(scripts); // Activity by event type const activityByType = await db .select({ eventType: scriptAnalytics.eventType, count: count(scriptAnalytics.id), }) .from(scriptAnalytics) .where(gte(scriptAnalytics.createdAt, startDate)) .groupBy(scriptAnalytics.eventType); // Most popular scripts const popularScripts = await db .select({ scriptId: scriptAnalytics.scriptId, scriptName: scripts.name, views: count(scriptAnalytics.id), }) .from(scriptAnalytics) .innerJoin(scripts, eq(scriptAnalytics.scriptId, scripts.id)) .where( and( eq(scriptAnalytics.eventType, 'view'), gte(scriptAnalytics.createdAt, startDate) ) ) .groupBy(scriptAnalytics.scriptId, scripts.name) .orderBy(desc(count(scriptAnalytics.id))) .limit(10); // Daily activity trends const dailyTrends = await db .select({ date: sql`DATE(${scriptAnalytics.createdAt})`, views: sql`SUM(CASE WHEN ${scriptAnalytics.eventType} = 'view' THEN 1 ELSE 0 END)`, downloads: sql`SUM(CASE WHEN ${scriptAnalytics.eventType} = 'download' THEN 1 ELSE 0 END)`, }) .from(scriptAnalytics) .where(gte(scriptAnalytics.createdAt, startDate)) .groupBy(sql`DATE(${scriptAnalytics.createdAt})`) .orderBy(sql`DATE(${scriptAnalytics.createdAt})`); return { totals, activityByType, popularScripts, dailyTrends, periodDays: days, }; } catch (error) { throw new ApiError(`Failed to get platform analytics: ${error}`, 500); } } // Get user analytics export async function getUserAnalytics(userId: string, days: number = 30) { try { const startDate = new Date(); startDate.setDate(startDate.getDate() - days); // User's scripts performance const userScriptsAnalytics = await db .select({ scriptId: scripts.id, scriptName: scripts.name, views: scripts.viewCount, downloads: scripts.downloadCount, rating: scripts.rating, ratingCount: scripts.ratingCount, }) .from(scripts) .where(eq(scripts.authorId, userId)) .orderBy(desc(scripts.viewCount)); // Recent activity on user's scripts const recentActivity = await db .select({ eventType: scriptAnalytics.eventType, count: count(scriptAnalytics.id), }) .from(scriptAnalytics) .innerJoin(scripts, eq(scriptAnalytics.scriptId, scripts.id)) .where( and( eq(scripts.authorId, userId), gte(scriptAnalytics.createdAt, startDate) ) ) .groupBy(scriptAnalytics.eventType); return { userScripts: userScriptsAnalytics, recentActivity, periodDays: days, }; } catch (error) { throw new ApiError(`Failed to get user analytics: ${error}`, 500); } }