'use server'; import { createClient } from '@/lib/supabase/server'; import { BottleMetadataSchema } from '@/types/whisky'; import { v4 as uuidv4 } from 'uuid'; export async function saveBottle( rawMetadata: any, base64Image: string | null, _ignoredUserId: string, // Keeping for signature compatibility preUploadedUrl?: string ) { const supabase = await createClient(); try { const metadata = BottleMetadataSchema.parse(rawMetadata); const { data: { user } } = await supabase.auth.getUser(); if (!user) { throw new Error('Nicht autorisiert oder Session abgelaufen.'); } const userId = user.id; let finalImageUrl = preUploadedUrl; // 1. Upload Image to Storage if not already uploaded if (!finalImageUrl && base64Image) { const base64Data = base64Image.split(',')[1] || base64Image; const buffer = Buffer.from(base64Data, 'base64'); const isWebp = base64Image.startsWith('data:image/webp'); const fileName = `${userId}/${uuidv4()}.${isWebp ? 'webp' : 'jpg'}`; const { error: uploadError } = await supabase.storage .from('bottles') .upload(fileName, buffer, { contentType: isWebp ? 'image/webp' : 'image/jpeg', upsert: true, }); if (uploadError) throw new Error(`Upload Error: ${uploadError.message}`); // Get Public URL const { data: { publicUrl } } = supabase.storage .from('bottles') .getPublicUrl(fileName); finalImageUrl = publicUrl; } if (!finalImageUrl) { throw new Error('Kein Bild zum Speichern vorhanden.'); } // 1.5 Deduplication Check // If a bottle with the same name/distillery was created by the same user in the last 5 minutes, // we treat it as a duplicate (likely from a race condition or double sync). const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString(); const { data: existingBottle } = await supabase .from('bottles') .select('*') .eq('user_id', userId) .eq('name', metadata.name) .eq('distillery', metadata.distillery) .gte('created_at', fiveMinutesAgo) .order('created_at', { ascending: false }) .limit(1) .maybeSingle(); if (existingBottle) { console.log('[saveBottle] Potential duplicate detected, returning existing bottle:', existingBottle.id); return { success: true, data: existingBottle }; } // 2. Save Metadata to Database const { data: bottleData, error: dbError } = await supabase .from('bottles') .insert({ user_id: userId, name: metadata.name, distillery: metadata.distillery, category: metadata.category, abv: metadata.abv, age: metadata.age, whiskybase_id: metadata.whiskybaseId, image_url: finalImageUrl, status: 'sealed', is_whisky: metadata.is_whisky ?? true, confidence: metadata.confidence ? Math.round(metadata.confidence * 100) : 100, distilled_at: metadata.distilled_at, bottled_at: metadata.bottled_at, batch_info: metadata.batch_info, purchase_price: metadata.purchase_price, suggested_tags: metadata.suggested_tags, suggested_custom_tags: metadata.suggested_custom_tags, }) .select() .single(); if (dbError) throw new Error(`Database Error: ${dbError.message}`); return { success: true, data: bottleData }; } catch (error) { console.error('Save Bottle Error:', error); return { success: false, error: error instanceof Error ? error.message : 'An unknown error occurred while saving.', }; } }