const { getSupabaseServiceClient } = require('../utils/supabase'); const { calculatePayout } = require('./payoutCalculator'); const { recalculatePerformance } = require('./performanceService'); async function createBet(userId, { legs, amount, book, bet_type, scan_session_id, placed_at }) { const supabase = getSupabaseServiceClient(); // Validate scan_session_id if provided if (scan_session_id) { const { data: session } = await supabase .from('scan_sessions') .select('id') .eq('id', scan_session_id) .eq('user_id', userId) .single(); if (!session) { const err = new Error('Scan session not found or does not belong to user'); err.statusCode = 404; throw err; } } const legsOdds = legs.map((l) => l.odds).filter((o) => o != null); const potentialPayout = calculatePayout(amount, bet_type, legsOdds); // Compute total odds for slip_data let totalOdds = null; if (legsOdds.length === 1) { totalOdds = legsOdds[0]; } else if (legsOdds.length > 1) { // Convert to decimal, multiply, convert back to American let decimalProduct = 1; for (const odds of legsOdds) { decimalProduct *= odds < 0 ? 1 + (100 / Math.abs(odds)) : 1 + (odds / 100); } totalOdds = decimalProduct >= 2 ? Math.round((decimalProduct - 1) * 100) : Math.round(-100 / (decimalProduct - 1)); } const slipData = { legs, total_odds: totalOdds, scan_session_id: scan_session_id || null, }; const { data: bet, error } = await supabase .from('bets') .insert({ user_id: userId, amount, potential_payout: potentialPayout, slip_data: slipData, book, bet_type, submission_method: 'quickslip', status: 'pending', placed_at: placed_at || new Date().toISOString(), }) .select('id, status, amount, potential_payout, bet_type, book, created_at') .single(); if (error) throw error; return { bet_id: bet.id, status: bet.status, amount: parseFloat(bet.amount), potential_payout: parseFloat(bet.potential_payout), bet_type: bet.bet_type, book: bet.book, legs: legs.length, scan_session_id: scan_session_id || null, created_at: bet.created_at, }; } async function createBetFromScreenshot(userId, { legs, amount, book, bet_type, scan_session_id }) { // Same as quickslip but with submission_method = 'screenshot' const supabase = getSupabaseServiceClient(); if (scan_session_id) { const { data: session } = await supabase .from('scan_sessions') .select('id') .eq('id', scan_session_id) .eq('user_id', userId) .single(); if (!session) { const err = new Error('Scan session not found or does not belong to user'); err.statusCode = 404; throw err; } } const legsOdds = legs.map((l) => l.odds).filter((o) => o != null); const potentialPayout = calculatePayout(amount, bet_type, legsOdds); const slipData = { legs, scan_session_id: scan_session_id || null, }; const { data: bet, error } = await supabase .from('bets') .insert({ user_id: userId, amount, potential_payout: potentialPayout, slip_data: slipData, book, bet_type, submission_method: 'screenshot', status: 'pending', placed_at: new Date().toISOString(), }) .select('id, status, amount, potential_payout, bet_type, book, created_at') .single(); if (error) throw error; return { bet_id: bet.id, status: bet.status, amount: parseFloat(bet.amount), potential_payout: parseFloat(bet.potential_payout), bet_type: bet.bet_type, book: bet.book, legs: legs.length, scan_session_id: scan_session_id || null, created_at: bet.created_at, }; } async function settleBet(userId, betId, { status, leg_outcomes }) { const supabase = getSupabaseServiceClient(); // Fetch the bet const { data: bet, error: fetchError } = await supabase .from('bets') .select('*') .eq('id', betId) .eq('user_id', userId) .single(); if (fetchError || !bet) { const err = new Error('Bet not found'); err.statusCode = 404; throw err; } if (bet.status !== 'pending') { const err = new Error('Bet already settled'); err.statusCode = 422; throw err; } // Update bet status const settledAt = new Date().toISOString(); const { error: updateError } = await supabase .from('bets') .update({ status, settled_at: settledAt }) .eq('id', betId); if (updateError) throw updateError; // Calculate profit const amount = parseFloat(bet.amount); const payout = parseFloat(bet.potential_payout || 0); let profit = 0; if (status === 'won') profit = payout - amount; else if (status === 'lost') profit = -amount; // Recalculate performance await recalculatePerformance(userId); return { bet_id: betId, status, settled_at: settledAt, amount, potential_payout: payout, profit: Math.round(profit * 100) / 100, }; } async function listBets(userId, { status, book, limit = 20, offset = 0 }) { const supabase = getSupabaseServiceClient(); let query = supabase .from('bets') .select('*', { count: 'exact' }) .eq('user_id', userId) .order('placed_at', { ascending: false }) .range(offset, offset + limit - 1); if (status) query = query.eq('status', status); if (book) query = query.eq('book', book); const { data: bets, count, error } = await query; if (error) throw error; return { bets: bets || [], total: count || 0, limit, offset, }; } module.exports = { createBet, createBetFromScreenshot, settleBet, listBets };