'use server'; import { createClient } from '@/lib/supabase/server'; import { checkIsAdmin } from './track-api-usage'; import { addCredits, getUserCredits } from './credit-service'; import { AdminCreditUpdateSchema, AdminSettingsSchema } from '@/types/whisky'; interface UserWithCredits { id: string; email: string; username: string; balance: number; total_purchased: number; total_used: number; daily_limit: number | null; google_search_cost: number; gemini_ai_cost: number; last_active?: string; } /** * Get all users with their credit information (admin only) */ export async function getAllUsersWithCredits(): Promise { try { const supabase = await createClient(); // Check if current user is admin const { data: { user } } = await supabase.auth.getUser(); if (!user) { console.log('[getAllUsersWithCredits] No user found'); return []; } const isAdmin = await checkIsAdmin(user.id); if (!isAdmin) { console.log('[getAllUsersWithCredits] User is not admin'); return []; } console.log('[getAllUsersWithCredits] Fetching profiles...'); // Get all users with their profiles const { data: profiles, error: profilesError } = await supabase .from('profiles') .select('id, username'); if (profilesError) { console.error('Error fetching profiles:', profilesError); return []; } console.log('[getAllUsersWithCredits] Found profiles:', profiles?.length); // Get all user credits const { data: credits, error: creditsError } = await supabase .from('user_credits') .select('*'); if (creditsError) { console.error('Error fetching credits:', creditsError); } console.log('[getAllUsersWithCredits] Found credits:', credits?.length); // Combine data - we'll use profile id as email fallback const usersWithCredits: UserWithCredits[] = profiles?.map(profile => { const userCredits = credits?.find(c => c.user_id === profile.id); return { id: profile.id, email: profile.id.substring(0, 8) + '...', // Show partial ID as placeholder username: profile.username || 'Unknown', balance: userCredits?.balance || 0, total_purchased: userCredits?.total_purchased || 0, total_used: userCredits?.total_used || 0, daily_limit: userCredits?.daily_limit || null, google_search_cost: userCredits?.google_search_cost || 1, gemini_ai_cost: userCredits?.gemini_ai_cost || 1, last_active: undefined }; }) || []; console.log('[getAllUsersWithCredits] Returning users:', usersWithCredits.length); return usersWithCredits; } catch (err) { console.error('Error in getAllUsersWithCredits:', err); return []; } } /** * Update user's credit balance (admin only) */ export async function updateUserCredits( userId: string, newBalance: number, reason: string ): Promise<{ success: boolean; error?: string }> { try { const validated = AdminCreditUpdateSchema.parse({ userId, newBalance, reason }); const supabase = await createClient(); // Check if current user is admin const { data: { user } } = await supabase.auth.getUser(); if (!user) return { success: false, error: 'Not authenticated' }; const isAdmin = await checkIsAdmin(user.id); if (!isAdmin) return { success: false, error: 'Not authorized' }; // Get current credits const currentCredits = await getUserCredits(validated.userId); if (!currentCredits) { return { success: false, error: 'User credits not found' }; } const difference = validated.newBalance - currentCredits.balance; // Use addCredits which handles the transaction logging const result = await addCredits(validated.userId, difference, validated.reason, user.id); return result; } catch (err) { console.error('Error in updateUserCredits:', err); return { success: false, error: err instanceof Error ? err.message : 'Failed to update credits' }; } } /** * Set user's daily limit (admin only) */ export async function setUserDailyLimit( userId: string, dailyLimit: number | null ): Promise<{ success: boolean; error?: string }> { try { const validated = AdminSettingsSchema.parse({ userId, dailyLimit }); const supabase = await createClient(); // Check if current user is admin const { data: { user } } = await supabase.auth.getUser(); if (!user) return { success: false, error: 'Not authenticated' }; const isAdmin = await checkIsAdmin(user.id); if (!isAdmin) return { success: false, error: 'Not authorized' }; const { error } = await supabase .from('user_credits') .update({ daily_limit: validated.dailyLimit }) .eq('user_id', validated.userId); if (error) { console.error('Error setting daily limit:', error); return { success: false, error: 'Failed to set daily limit' }; } return { success: true }; } catch (err) { console.error('Error in setUserDailyLimit:', err); return { success: false, error: err instanceof Error ? err.message : 'Failed to set daily limit' }; } } /** * Set user's API costs (admin only) */ export async function setUserApiCosts( userId: string, googleSearchCost: number, geminiAiCost: number ): Promise<{ success: boolean; error?: string }> { try { const validated = AdminSettingsSchema.parse({ userId, googleSearchCost, geminiAiCost }); const supabase = await createClient(); // Check if current user is admin const { data: { user } } = await supabase.auth.getUser(); if (!user) return { success: false, error: 'Not authenticated' }; const isAdmin = await checkIsAdmin(user.id); if (!isAdmin) return { success: false, error: 'Not authorized' }; const { error } = await supabase .from('user_credits') .update({ google_search_cost: validated.googleSearchCost, gemini_ai_cost: validated.geminiAiCost }) .eq('user_id', validated.userId); if (error) { console.error('Error setting API costs:', error); return { success: false, error: 'Failed to set API costs' }; } return { success: true }; } catch (err) { console.error('Error in setUserApiCosts:', err); return { success: false, error: err instanceof Error ? err.message : 'Failed to set API costs' }; } } /** * Bulk add credits to multiple users (admin only) */ export async function bulkAddCredits( userIds: string[], amount: number, reason: string ): Promise<{ success: boolean; processed: number; failed: number; error?: string }> { try { const supabase = await createClient(); // Check if current user is admin const { data: { user } } = await supabase.auth.getUser(); if (!user) return { success: false, processed: 0, failed: 0, error: 'Not authenticated' }; const isAdmin = await checkIsAdmin(user.id); if (!isAdmin) return { success: false, processed: 0, failed: 0, error: 'Not authorized' }; let processed = 0; let failed = 0; for (const userId of userIds) { const result = await addCredits(userId, amount, reason, user.id); if (result.success) { processed++; } else { failed++; } } return { success: true, processed, failed }; } catch (err) { console.error('Error in bulkAddCredits:', err); return { success: false, processed: 0, failed: 0, error: 'Failed to bulk add credits' }; } }