// lib/services/river_api_service.dart import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; import 'package:environment_monitoring_app/services/base_api_service.dart'; import 'package:environment_monitoring_app/services/telegram_service.dart'; // NOTE: RiverApiService still needs RiverInSituSamplingData import for its handle alert method, // but since the model file wasn't provided directly, we assume it's correctly handled by the caller/context. class RiverApiService { final BaseApiService _baseService; final TelegramService _telegramService; RiverApiService(this._baseService, this._telegramService); Future> getManualStations() { return _baseService.get('river/manual-stations'); } Future> getTriennialStations() { return _baseService.get('river/triennial-stations'); } // MODIFIED: Method now returns granular status tracking for API and Images. Future> submitInSituSample({ required Map formData, required Map imageFiles, required List>? appSettings, }) async { Map finalResult = { 'success': false, 'status': 'L1', // Default: Local Failure (Data failed) 'api_status': 'NOT_ATTEMPTED', 'image_upload_status': 'NOT_ATTEMPTED', 'message': 'Submission failed.', 'reportId': null, }; // --- Step 1: Submit Form Data as JSON --- debugPrint("Step 1: Submitting River In-Situ form data..."); final dataResult = await _baseService.post('river/manual/sample', formData); finalResult['api_status'] = dataResult['success'] == true ? 'SUCCESS' : 'FAILED'; if (dataResult['success'] != true) { finalResult['message'] = dataResult['message'] ?? 'Failed to submit river in-situ data (API failed).'; return finalResult; } // Update status and reportId upon successful data submission final recordId = dataResult['data']?['r_man_id']; finalResult['reportId'] = recordId?.toString(); if (recordId == null) { finalResult['api_status'] = 'FAILED'; finalResult['message'] = 'Data submitted, but server did not return a record ID.'; return finalResult; } final filesToUpload = {}; imageFiles.forEach((key, value) { if (value != null) filesToUpload[key] = value; }); // --- Step 2: Upload Image Files --- if (filesToUpload.isEmpty) { debugPrint("No images to upload. Finalizing submission."); finalResult['image_upload_status'] = 'NOT_REQUIRED'; // Final Status: S3 (Success, Data Only) finalResult['success'] = true; finalResult['status'] = 'S3'; finalResult['message'] = 'Data submitted successfully. No images were attached.'; _handleInSituSuccessAlert(formData, appSettings, isDataOnly: true); return finalResult; } debugPrint("Step 2: Uploading ${filesToUpload.length} images..."); final imageResult = await _baseService.postMultipart( endpoint: 'river/manual/images', // Separate endpoint for images fields: {'r_man_id': recordId.toString()}, // Link images to the submitted record ID files: filesToUpload, ); finalResult['image_upload_status'] = imageResult['success'] == true ? 'SUCCESS' : 'FAILED'; if (imageResult['success'] != true) { // Data submitted successfully, but images failed (L2/L4 equivalent) finalResult['success'] = true; // API data transfer was still successful finalResult['status'] = 'L2_PENDING_IMAGES'; finalResult['message'] = 'Data submitted, but image upload failed: ${imageResult['message']}'; _handleInSituSuccessAlert(formData, appSettings, isDataOnly: true); // Alert for data only return finalResult; } // --- Step 3: Full Success --- finalResult['success'] = true; finalResult['status'] = 'S2'; // S2 means Data+Images submitted finalResult['message'] = 'Data and images submitted successfully.'; _handleInSituSuccessAlert(formData, appSettings, isDataOnly: false); return finalResult; } // MODIFIED: Method now requires appSettings and calls the updated TelegramService. Future _handleInSituSuccessAlert(Map formData, List>? appSettings, {required bool isDataOnly}) async { try { final submissionType = isDataOnly ? "(Data Only)" : "(Data & Images)"; final stationName = formData['r_man_station_name'] ?? 'N/A'; final stationCode = formData['r_man_station_code'] ?? 'N/A'; final submissionDate = formData['r_man_date'] ?? DateFormat('yyyy-MM-dd').format(DateTime.now()); final submitter = formData['first_sampler_name'] ?? 'N/A'; final sondeID = formData['r_man_sondeID'] ?? 'N/A'; final distanceKm = double.tryParse(formData['r_man_distance_difference'] ?? '0') ?? 0; final distanceMeters = (distanceKm * 1000).toStringAsFixed(0); final distanceRemarks = formData['r_man_distance_difference_remarks'] ?? 'N/A'; final buffer = StringBuffer() ..writeln('✅ *River In-Situ Sample ${submissionType} Submitted:*') ..writeln() ..writeln('*Station Name & Code:* $stationName ($stationCode)') ..writeln('*Date of Submitted:* $submissionDate') ..writeln('*Submitted by User:* $submitter') ..writeln('*Sonde ID:* $sondeID') ..writeln('*Status of Submission:* Successful'); if (distanceKm > 0 || (distanceRemarks.isNotEmpty && distanceRemarks != 'N/A')) { buffer ..writeln() ..writeln('🔔 *Alert:*') ..writeln('*Distance from station:* $distanceMeters meters'); if (distanceRemarks.isNotEmpty && distanceRemarks != 'N/A') { buffer.writeln('*Remarks for distance:* $distanceRemarks'); } } final String message = buffer.toString(); // MODIFIED: Pass the appSettings list to the TelegramService methods. final bool wasSent = await _telegramService.sendAlertImmediately('river_in_situ', message, appSettings); if (!wasSent) { await _telegramService.queueMessage('river_in_situ', message, appSettings); } } catch (e) { debugPrint("Failed to handle River Telegram alert: $e"); } } }