import { serve } from "https://deno.land/std@0.190.0/http/server.ts"; import { createEdgeFunction, type EdgeFunctionContext } from '../_shared/edgeFunctionWrapper.ts'; import { corsHeaders } from '../_shared/cors.ts'; import { addSpanEvent } from '../_shared/logger.ts'; import { withEdgeRetry } from '../_shared/retryHelper.ts'; interface NotificationPayload { reportId: string; reportType: string; reportedEntityType: string; reportedEntityId: string; reporterName: string; reason: string; reportedAt: string; entityPreview: string; } const handler = async (req: Request, { supabase, span, requestId }: EdgeFunctionContext) => { const payload: NotificationPayload = await req.json(); addSpanEvent(span, 'processing_report_notification', { reportId: payload.reportId, reportType: payload.reportType, reportedEntityType: payload.reportedEntityType }); // Calculate relative time const reportedAt = new Date(payload.reportedAt); const now = new Date(); const diffMs = now.getTime() - reportedAt.getTime(); const diffMins = Math.floor(diffMs / 60000); let relativeTime: string; if (diffMins < 1) { relativeTime = 'just now'; } else if (diffMins < 60) { relativeTime = `${diffMins} minute${diffMins === 1 ? '' : 's'} ago`; } else { const diffHours = Math.floor(diffMins / 60); relativeTime = `${diffHours} hour${diffHours === 1 ? '' : 's'} ago`; } // Determine priority based on report type and age let priority: string; const criticalTypes = ['harassment', 'offensive']; const isUrgent = diffMins < 5; if (criticalTypes.includes(payload.reportType) || isUrgent) { priority = 'high'; } else if (diffMins < 30) { priority = 'medium'; } else { priority = 'low'; } // Fetch the workflow ID for report alerts const { data: template, error: templateError } = await supabase .from('notification_templates') .select('workflow_id') .eq('workflow_id', 'report-alert') .eq('is_active', true) .maybeSingle(); if (templateError) { addSpanEvent(span, 'workflow_fetch_failed', { error: templateError.message }); throw new Error(`Failed to fetch workflow: ${templateError.message}`); } if (!template) { addSpanEvent(span, 'no_active_workflow', {}); return new Response( JSON.stringify({ success: false, error: 'No active report-alert workflow configured', }), { status: 400 } ); } // Fetch reported entity name let reportedEntityName = 'Unknown'; try { if (payload.reportedEntityType === 'review') { const { data: review } = await supabase .from('reviews') .select('ride:rides(name), park:parks(name)') .eq('id', payload.reportedEntityId) .maybeSingle(); reportedEntityName = review?.ride?.name || review?.park?.name || 'Review'; } else if (payload.reportedEntityType === 'profile') { const { data: profile } = await supabase .from('profiles') .select('display_name, username') .eq('user_id', payload.reportedEntityId) .maybeSingle(); reportedEntityName = profile?.display_name || profile?.username || 'User Profile'; } else if (payload.reportedEntityType === 'content_submission') { const { data: metadata } = await supabase .from('submission_metadata') .select('metadata_value') .eq('submission_id', payload.reportedEntityId) .eq('metadata_key', 'name') .maybeSingle(); reportedEntityName = metadata?.metadata_value || 'Submission'; } } catch (error) { addSpanEvent(span, 'entity_name_fetch_failed', { error: error instanceof Error ? error.message : String(error) }); } // Build enhanced notification payload const notificationPayload = { baseUrl: 'https://www.thrillwiki.com', reportId: payload.reportId, reportType: payload.reportType, reportedEntityType: payload.reportedEntityType, reportedEntityId: payload.reportedEntityId, reporterName: payload.reporterName, reason: payload.reason, entityPreview: payload.entityPreview, reportedEntityName, reportedAt: payload.reportedAt, relativeTime, priority, }; addSpanEvent(span, 'triggering_notification', { workflowId: template.workflow_id, priority }); // Invoke the trigger-notification function with retry const result = await withEdgeRetry( async () => { const { data, error } = await supabase.functions.invoke( 'trigger-notification', { body: { workflowId: template.workflow_id, topicKey: 'moderation-reports', payload: notificationPayload, }, } ); if (error) { const enhancedError = new Error(error.message || 'Notification trigger failed'); (enhancedError as any).status = error.status; throw enhancedError; } return data; }, { maxAttempts: 3, baseDelay: 1000 }, requestId, 'trigger-report-notification' ); addSpanEvent(span, 'notification_sent', { transactionId: result?.transactionId }); return { success: true, transactionId: result?.transactionId, payload: notificationPayload, }; }; serve(createEdgeFunction({ name: 'notify-moderators-report', requireAuth: false, useServiceRole: true, corsHeaders, enableTracing: true, logRequests: true, }, handler));