// lib/features/booking/providers/checkout_provider.dart import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../../../core/api/api_endpoints.dart'; import '../../../core/utils/error_utils.dart'; import '../models/booking_models.dart'; import '../services/booking_service.dart'; enum CheckoutStep { tickets, details, payment, confirmation } class CheckoutProvider extends ChangeNotifier { final BookingService _service = BookingService(); // Event being booked int? eventId; String eventName = ''; // Step tracking CheckoutStep currentStep = CheckoutStep.tickets; // Ticket selection List availableTickets = []; List cart = []; // Shipping ShippingDetails? shippingDetails; // Coupon / promo String? couponCode; double discountAmount = 0.0; String? promoMessage; bool promoApplied = false; // Status bool loading = false; String? error; String? paymentId; /// Initialize checkout for an event. Future initForEvent(int eventId, String eventName) async { this.eventId = eventId; this.eventName = eventName; currentStep = CheckoutStep.tickets; cart = []; shippingDetails = null; couponCode = null; discountAmount = 0.0; promoMessage = null; promoApplied = false; paymentId = null; error = null; loading = true; notifyListeners(); try { availableTickets = await _service.getTicketMeta(eventId); } catch (e) { error = userFriendlyError(e); } finally { loading = false; notifyListeners(); } } /// Add or update cart item. void setTicketQuantity(TicketMetaModel ticket, int qty) { cart.removeWhere((c) => c.ticket.id == ticket.id); if (qty > 0) { cart.add(CartItemModel(ticket: ticket, quantity: qty)); } notifyListeners(); } double get subtotal => cart.fold(0, (sum, item) => sum + item.subtotal); double get total => subtotal - discountAmount; bool get hasItems => cart.isNotEmpty; /// Move to next step. void nextStep() { if (currentStep == CheckoutStep.tickets && hasItems) { currentStep = CheckoutStep.details; } else if (currentStep == CheckoutStep.details && shippingDetails != null) { currentStep = CheckoutStep.payment; } notifyListeners(); } /// Move to previous step. void previousStep() { if (currentStep == CheckoutStep.payment) { currentStep = CheckoutStep.details; } else if (currentStep == CheckoutStep.details) { currentStep = CheckoutStep.tickets; } notifyListeners(); } /// Set shipping details from form. void setShipping(ShippingDetails details) { shippingDetails = details; notifyListeners(); } /// Apply a promo code against the backend. Future applyPromo(String code) async { if (code.trim().isEmpty) return false; loading = true; error = null; notifyListeners(); try { final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('access_token') ?? ''; final response = await http.post( Uri.parse('${ApiEndpoints.baseUrl}/bookings/apply-promo/'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({'code': code.trim(), 'event_id': eventId}), ); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['valid'] == true) { discountAmount = (data['discount_amount'] as num?)?.toDouble() ?? 0.0; couponCode = code.trim(); promoMessage = data['message'] as String? ?? 'Promo applied!'; promoApplied = true; notifyListeners(); return true; } else { promoMessage = data['message'] as String? ?? 'Invalid promo code'; promoApplied = false; discountAmount = 0.0; couponCode = null; notifyListeners(); return false; } } else { promoMessage = 'Could not apply promo code'; return false; } } catch (e) { promoMessage = 'Could not apply promo code'; return false; } finally { loading = false; notifyListeners(); } } /// Remove applied promo code. void resetPromo() { discountAmount = 0.0; couponCode = null; promoMessage = null; promoApplied = false; notifyListeners(); } /// Process checkout on backend. Future> processCheckout() async { loading = true; error = null; notifyListeners(); try { final tickets = cart.map((c) => { 'ticket_meta_id': c.ticket.id, 'quantity': c.quantity, }).toList(); final res = await _service.processCheckout( eventId: eventId!, tickets: tickets, shippingDetails: shippingDetails?.toJson() ?? {}, couponCode: couponCode, ); return res; } catch (e) { error = userFriendlyError(e); rethrow; } finally { loading = false; notifyListeners(); } } /// Mark payment as complete. void markPaymentSuccess(String id) { paymentId = id; currentStep = CheckoutStep.confirmation; notifyListeners(); } /// Reset checkout state. void reset() { eventId = null; eventName = ''; currentStep = CheckoutStep.tickets; availableTickets = []; cart = []; shippingDetails = null; couponCode = null; discountAmount = 0.0; promoMessage = null; promoApplied = false; paymentId = null; error = null; loading = false; notifyListeners(); } }