import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:http/http.dart' as http; import '../config/app_config.dart'; import '../models/booking.dart'; import 'auth_service.dart'; class BookingService { final AuthService _authService = AuthService(); Map get _headers { final headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', }; if (_authService.token != null) { headers['Authorization'] = 'Bearer ${_authService.token}'; } return headers; } Future> getBookingHistory() async { try { final response = await http.get( Uri.parse('${AppConfig.baseUrl}/bookings'), headers: _headers, ); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return []; } if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['success'] == true) { final List items = data['data']['data'] ?? data['data'] ?? []; return items .map( (item) => Booking.fromJson(Map.from(item as Map)), ) .toList(); } } return []; } catch (_) { return []; } } Future> _createPengajuan( Map body, ) async { try { final response = await http .post( Uri.parse('${AppConfig.baseUrl}/bookings'), headers: _headers, body: jsonEncode(body), ) .timeout(const Duration(seconds: 30)); final data = jsonDecode(response.body); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return { 'success': false, 'message': 'Sesi habis, silakan login ulang.', }; } if (response.statusCode == 201 && data['success'] == true) { return { 'success': true, 'message': data['message'], 'booking': Booking.fromJson( Map.from(data['data'] as Map), ), }; } return { 'success': false, 'message': data['message'] ?? 'Gagal mengirim pengajuan.', 'errors': data['errors'], }; } catch (e) { return {'success': false, 'message': 'Terjadi kesalahan: $e'}; } } Future> createSurvey({ required int kontrakanId, required DateTime tanggalSurvei, required String jamSurvei, String? catatan, }) async { final body = { 'kontrakan_id': kontrakanId, 'jenis_pengajuan': 'survei', 'tanggal_survei': tanggalSurvei.toIso8601String().split('T')[0], 'jam_survei': jamSurvei, }; if (catatan != null && catatan.trim().isNotEmpty) { body['catatan'] = catatan.trim(); } return _createPengajuan(body); } Future> createSewa({ required int kontrakanId, required DateTime tanggalMulai, required int durasiBulan, String? catatan, File? ktpPhoto, }) async { try { final request = http.MultipartRequest( 'POST', Uri.parse('${AppConfig.baseUrl}/bookings'), ); if (_authService.token != null) { request.headers['Authorization'] = 'Bearer ${_authService.token}'; } request.headers['Accept'] = 'application/json'; request.fields['kontrakan_id'] = kontrakanId.toString(); request.fields['jenis_pengajuan'] = 'sewa'; request.fields['tanggal_mulai'] = tanggalMulai.toIso8601String().split( 'T', )[0]; request.fields['durasi_bulan'] = durasiBulan.toString(); if (catatan != null && catatan.trim().isNotEmpty) { request.fields['catatan'] = catatan.trim(); } if (ktpPhoto != null) { request.files.add( await http.MultipartFile.fromPath('ktp_photo', ktpPhoto.path), ); } final streamedResponse = await request.send().timeout( const Duration(seconds: 30), ); final response = await http.Response.fromStream(streamedResponse); final data = response.body.isNotEmpty ? jsonDecode(response.body) : {}; if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return { 'success': false, 'message': 'Sesi habis, silakan login ulang.', }; } if (response.statusCode == 201 && data['success'] == true) { return { 'success': true, 'message': data['message'], 'booking': Booking.fromJson(data['data']), }; } return { 'success': false, 'message': data['message'] ?? 'Gagal mengirim pengajuan sewa.', 'errors': data['errors'], }; } catch (e) { return {'success': false, 'message': 'Terjadi kesalahan: $e'}; } } Future> createBooking({ required int kontrakanId, required DateTime tanggalMulai, required int durasiBulan, String? catatan, File? paymentProof, }) { return createSewa( kontrakanId: kontrakanId, tanggalMulai: tanggalMulai, durasiBulan: durasiBulan, catatan: catatan, ); } Future> cancelBooking(int bookingId) async { try { final response = await http.post( Uri.parse('${AppConfig.baseUrl}/bookings/$bookingId/cancel'), headers: _headers, ); final data = jsonDecode(response.body); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return { 'success': false, 'message': 'Sesi habis, silakan login ulang.', }; } if (response.statusCode == 200 && data['success'] == true) { return {'success': true, 'message': data['message']}; } return { 'success': false, 'message': data['message'] ?? 'Gagal membatalkan pengajuan.', }; } catch (e) { return {'success': false, 'message': 'Terjadi kesalahan: $e'}; } } Future getBookingById(int id) async { try { final response = await http.get( Uri.parse('${AppConfig.baseUrl}/bookings/$id'), headers: _headers, ); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return null; } if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['success'] == true) { return Booking.fromJson( Map.from(data['data'] as Map), ); } } return null; } catch (_) { return null; } } Future> uploadPaymentProof( int bookingId, File imageFile, ) async { try { final request = http.MultipartRequest( 'POST', Uri.parse('${AppConfig.baseUrl}/bookings/$bookingId/payment-proof'), ); if (_authService.token != null) { request.headers['Authorization'] = 'Bearer ${_authService.token}'; request.headers['Accept'] = 'application/json'; } request.files.add( await http.MultipartFile.fromPath('payment_proof', imageFile.path), ); final streamedResponse = await request.send().timeout( const Duration(seconds: 30), ); final response = await http.Response.fromStream(streamedResponse); final data = jsonDecode(response.body); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return { 'success': false, 'message': 'Sesi habis, silakan login ulang.', }; } if (response.statusCode == 200 && data['success'] == true) { return { 'success': true, 'message': data['message'] ?? 'Bukti pembayaran berhasil diunggah.', 'booking': Booking.fromJson( Map.from(data['data'] as Map), ), }; } return { 'success': false, 'message': data['message'] ?? 'Gagal mengunggah bukti pembayaran.', }; } catch (e) { return {'success': false, 'message': 'Terjadi kesalahan: $e'}; } } Future getPaymentProofBytes(int bookingId) async { try { final headers = {'Accept': 'image/*'}; if (_authService.token != null) { headers['Authorization'] = 'Bearer ${_authService.token}'; } final response = await http .get( Uri.parse('${AppConfig.baseUrl}/bookings/$bookingId/payment-proof'), headers: headers, ) .timeout(const Duration(seconds: 30)); if (response.statusCode == 401) { await _authService.handleUnauthorized(response.statusCode); return null; } if (response.statusCode == 200) { return response.bodyBytes; } return null; } catch (_) { return null; } } }