import { serve } from "https://deno.land/std@0.190.0/http/server.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", }; interface GoogleOAuthConfig { client_id: string; client_secret: string; refresh_token: string; access_token?: string; expires_at?: number; } interface DeleteEventRequest { session_id: string; } // Function to get access token from refresh token (OAuth2) async function getGoogleAccessToken(oauthConfig: GoogleOAuthConfig): Promise<{ access_token: string; expires_in: number }> { try { console.log("Refreshing access token for calendar event deletion..."); const tokenRequest = { client_id: oauthConfig.client_id, client_secret: oauthConfig.client_secret, refresh_token: oauthConfig.refresh_token, grant_type: "refresh_token", }; const response = await fetch("https://oauth2.googleapis.com/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams(tokenRequest), }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Token exchange failed: ${errorText}`); } const data = await response.json(); if (!data.access_token) { throw new Error("No access token in response"); } return { access_token: data.access_token, expires_in: data.expires_in || 3600 }; } catch (error: any) { console.error("Error getting Google access token:", error); throw error; } } serve(async (req: Request): Promise => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const body: DeleteEventRequest = await req.json(); console.log("[DELETE-CALENDAR-EVENT] Deleting event for session:", body.session_id); const supabaseUrl = Deno.env.get("SUPABASE_URL")!; const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const supabase = createClient(supabaseUrl, supabaseServiceKey); // Get session data with calendar_event_id const { data: session, error: sessionError } = await supabase .from("consulting_sessions") .select("id, calendar_event_id, user_id") .eq("id", body.session_id) .single(); if (sessionError || !session) { console.error("[DELETE-CALENDAR-EVENT] Session not found:", sessionError); return new Response( JSON.stringify({ success: false, error: "Session not found" }), { status: 404, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } if (!session.calendar_event_id) { console.log("[DELETE-CALENDAR-EVENT] No calendar_event_id found, skipping deletion"); return new Response( JSON.stringify({ success: true, message: "No calendar event to delete" }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } // Get OAuth config const { data: settings } = await supabase .from("platform_settings") .select("integration_google_calendar_id, google_oauth_config") .single(); const calendarId = settings?.integration_google_calendar_id; const oauthConfigJson = settings?.google_oauth_config; if (!calendarId || !oauthConfigJson) { console.log("[DELETE-CALENDAR-EVENT] Calendar not configured, skipping deletion"); return new Response( JSON.stringify({ success: true, message: "Calendar not configured" }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } // Parse OAuth config let oauthConfig: GoogleOAuthConfig; try { oauthConfig = JSON.parse(oauthConfigJson); } catch (error) { console.error("[DELETE-CALENDAR-EVENT] Failed to parse OAuth config"); return new Response( JSON.stringify({ success: false, error: "Invalid OAuth config" }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } // Get access token let accessToken: string; const now = Math.floor(Date.now() / 1000); if (oauthConfig.access_token && oauthConfig.expires_at && oauthConfig.expires_at > now + 60) { accessToken = oauthConfig.access_token; } else { const tokenData = await getGoogleAccessToken(oauthConfig); accessToken = tokenData.access_token; // Update cached token const newExpiresAt = now + tokenData.expires_in; const updatedConfig = { ...oauthConfig, access_token: accessToken, expires_at: newExpiresAt }; await supabase .from("platform_settings") .update({ google_oauth_config: JSON.stringify(updatedConfig) }) .eq("id", settings.id); } // Delete event from Google Calendar console.log(`[DELETE-CALENDAR-EVENT] Deleting event ${session.calendar_event_id} from calendar ${calendarId}`); const deleteResponse = await fetch( `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(session.calendar_event_id)}`, { method: "DELETE", headers: { "Authorization": `Bearer ${accessToken}`, }, } ); if (!deleteResponse.ok) { if (deleteResponse.status === 410) { // Event already deleted (Gone) console.log("[DELETE-CALENDAR-EVENT] Event already deleted (410)"); } else { const errorText = await deleteResponse.text(); console.error("[DELETE-CALENDAR-EVENT] Failed to delete event:", errorText); // Don't fail the operation, just log it } } else { console.log("[DELETE-CALENDAR-EVENT] Event deleted successfully"); } // Clear calendar_event_id from session await supabase .from("consulting_sessions") .update({ calendar_event_id: null }) .eq("id", body.session_id); return new Response( JSON.stringify({ success: true, message: "Calendar event deleted" }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { console.error("[DELETE-CALENDAR-EVENT] Error:", error); return new Response( JSON.stringify({ success: false, error: error.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });