import { createClient } from "https://esm.sh/@supabase/supabase-js@2.39.3"; const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type, x-supabase-client-platform, x-supabase-client-platform-version, x-supabase-client-runtime, x-supabase-client-runtime-version", }; // Called after SetupIntent succeeds to save enrollment Deno.serve(async (req) => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const supabaseUrl = Deno.env.get("SUPABASE_URL")!; const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const supabase = createClient(supabaseUrl, supabaseServiceKey); const authHeader = req.headers.get("Authorization"); if (!authHeader) { return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } const token = authHeader.replace("Bearer ", ""); const { data: { user }, error: authError, } = await supabase.auth.getUser(token); if (authError || !user) { return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } const body = await req.json(); const { setup_intent_id, association_id, owner_id, unit_id, customer_id, payment_method_type, } = body; if (!setup_intent_id || !association_id || !customer_id) { return new Response( JSON.stringify({ error: "Missing required fields" }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" }, } ); } // Get Stripe mapping to retrieve the payment method from SetupIntent const { data: mapping } = await supabase .from("stripe_account_mappings") .select("stripe_secret_key") .eq("association_id", association_id) .eq("is_active", true) .maybeSingle(); if (!mapping?.stripe_secret_key) { return new Response( JSON.stringify({ error: "No Stripe configuration found" }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" }, } ); } // Retrieve SetupIntent to get payment_method const siRes = await fetch( `https://api.stripe.com/v1/setup_intents/${setup_intent_id}`, { headers: { Authorization: `Bearer ${mapping.stripe_secret_key}`, }, } ); const siData = await siRes.json(); if (!siRes.ok || siData.status !== "succeeded") { return new Response( JSON.stringify({ error: "SetupIntent not successful", status: siData.status, }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" }, } ); } const paymentMethodId = siData.payment_method; // Deactivate any existing enrollment for this user+association await supabase .from("autopay_enrollments") .update({ is_active: false }) .eq("association_id", association_id) .eq("enrolled_by", user.id) .eq("is_active", true); // Insert new enrollment const { data: enrollment, error: insertError } = await supabase .from("autopay_enrollments") .insert({ association_id, owner_id: owner_id || null, unit_id: unit_id || null, stripe_customer_id: customer_id, stripe_payment_method_id: paymentMethodId, payment_method_type: payment_method_type || "card", is_active: true, enrolled_by: user.id, }) .select() .single(); if (insertError) { console.error("Insert error:", insertError); return new Response( JSON.stringify({ error: "Failed to save enrollment" }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" }, } ); } return new Response(JSON.stringify({ success: true, enrollment }), { status: 200, headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } catch (err: unknown) { console.error("Error in confirm-autopay:", err); const message = err instanceof Error ? err.message : "Internal server error"; return new Response(JSON.stringify({ error: message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" }, }); } });