// lib/models/tarball_data.dart import 'dart:io'; import 'dart:convert'; import 'package:environment_monitoring_app/models/marine_manual_npe_report_data.dart'; /// This class holds all the data collected across the multi-step tarball sampling form. /// It acts as a temporary data container that is passed between screens. class TarballSamplingData { // --- Step 1 Data: Collected in TarballSamplingStep1 --- String? firstSampler; int? firstSamplerUserId; Map? secondSampler; // Holds the full user map for the 2nd sampler String? samplingDate; String? samplingTime; String? selectedStateName; String? selectedCategoryName; Map? selectedStation; // Holds the full station map String? stationLatitude; String? stationLongitude; String? currentLatitude; String? currentLongitude; double? distanceDifference; String? distanceDifferenceRemarks; // --- Step 2 Data: Collected in TarballSamplingStep2 --- int? classificationId; // NECESSARY CHANGE: Add property to hold the full classification object. Map? selectedClassification; File? leftCoastalViewImage; File? rightCoastalViewImage; File? verticalLinesImage; File? horizontalLineImage; File? optionalImage1; String? optionalRemark1; File? optionalImage2; String? optionalRemark2; File? optionalImage3; String? optionalRemark3; File? optionalImage4; String? optionalRemark4; // --- Step 3 Data: For handling the submission response --- String? reportId; String? submissionStatus; String? submissionMessage; /// Converts tarball data into a pre-filled NPE Report data object. MarineManualNpeReportData toNpeReportData() { final npeData = MarineManualNpeReportData(); npeData.firstSamplerName = firstSampler; npeData.firstSamplerUserId = firstSamplerUserId; npeData.eventDate = samplingDate; npeData.eventTime = samplingTime; npeData.selectedStation = selectedStation; npeData.latitude = currentLatitude; npeData.longitude = currentLongitude; npeData.stateName = selectedStateName; // Pre-tick the relevant observation for a tarball event. npeData.fieldObservations['Observation of tar balls'] = true; return npeData; } /// Generates a formatted Telegram alert message for successful submissions. String generateTelegramAlertMessage({required bool isDataOnly}) { final submissionType = isDataOnly ? "(Data Only)" : "(Data & Images)"; final stationName = selectedStation?['tbl_station_name'] ?? 'N/A'; final stationCode = selectedStation?['tbl_station_code'] ?? 'N/A'; // This logic now correctly uses the full classification object if available. final classification = selectedClassification?['classification_name'] ?? classificationId?.toString() ?? 'N/A'; final buffer = StringBuffer() ..writeln('✅ *Tarball Sample $submissionType Submitted:*') ..writeln() ..writeln('*Station Name & Code:* $stationName ($stationCode)') ..writeln('*Date of Submission:* $samplingDate') ..writeln('*Submitted by User:* $firstSampler') ..writeln('*Classification:* $classification') ..writeln('*Status of Submission:* Successful'); // Add distance alert if relevant if (distanceDifference != null && distanceDifference! > 0) { buffer ..writeln() ..writeln('🔔 *Alert:*') ..writeln('*Distance from station:* ${(distanceDifference! * 1000).toStringAsFixed(0)} meters'); if (distanceDifferenceRemarks != null && distanceDifferenceRemarks!.isNotEmpty) { buffer.writeln('*Remarks for distance:* $distanceDifferenceRemarks'); } } return buffer.toString(); } /// Converts the form's text and selection data into a Map suitable for JSON encoding. /// This map will be sent as the body of the first API request. Map toFormData() { final Map data = { // Required fields that were missing or not being sent correctly 'station_id': selectedStation?['station_id']?.toString() ?? '', 'sampling_date': samplingDate ?? '', 'sampling_time': samplingTime ?? '', 'classification_id': classificationId?.toString() ?? '', 'first_sampler_user_id': firstSamplerUserId?.toString() ?? '', // Optional fields 'second_sampler_user_id': secondSampler?['user_id']?.toString() ?? '', 'current_latitude': currentLatitude ?? '', 'current_longitude': currentLongitude ?? '', 'distance_difference': distanceDifference?.toString() ?? '', 'distance_remarks': distanceDifferenceRemarks ?? '', 'optional_photo_remark_01': optionalRemark1 ?? '', 'optional_photo_remark_02': optionalRemark2 ?? '', 'optional_photo_remark_03': optionalRemark3 ?? '', 'optional_photo_remark_04': optionalRemark4 ?? '', // Human-readable names for the Telegram alert on the server-side 'tbl_station_name': selectedStation?['tbl_station_name']?.toString() ?? '', 'tbl_station_code': selectedStation?['tbl_station_code']?.toString() ?? '', 'first_sampler_name': firstSampler ?? '', 'classification_name': selectedClassification?['classification_name']?.toString() ?? '', }; return data; } /// Gathers all non-null image files into a Map. /// This map is used to build the multipart request for the second API call (image upload). Map toImageFiles() { return { 'left_side_coastal_view': leftCoastalViewImage, 'right_side_coastal_view': rightCoastalViewImage, 'drawing_vertical_lines': verticalLinesImage, 'drawing_horizontal_line': horizontalLineImage, 'optional_photo_01': optionalImage1, 'optional_photo_02': optionalImage2, 'optional_photo_03': optionalImage3, 'optional_photo_04': optionalImage4, }; } /// Creates a single JSON object with all submission data, mimicking 'db.json' Map toDbJson() { return { 'firstSampler': firstSampler, 'firstSamplerUserId': firstSamplerUserId, 'secondSampler': secondSampler, 'samplingDate': samplingDate, 'samplingTime': samplingTime, 'selectedStateName': selectedStateName, 'selectedCategoryName': selectedCategoryName, 'selectedStation': selectedStation, 'stationLatitude': stationLatitude, 'stationLongitude': stationLongitude, 'currentLatitude': currentLatitude, 'currentLongitude': currentLongitude, 'distanceDifference': distanceDifference, 'distanceDifferenceRemarks': distanceDifferenceRemarks, 'classificationId': classificationId, 'selectedClassification': selectedClassification, 'optionalRemark1': optionalRemark1, 'optionalRemark2': optionalRemark2, 'optionalRemark3': optionalRemark3, 'optionalRemark4': optionalRemark4, 'reportId': reportId, 'submissionStatus': submissionStatus, 'submissionMessage': submissionMessage, }; } /// Creates a JSON object for basic form info, mimicking 'basic_form.json'. Map toBasicFormJson() { return { 'tech_name': firstSampler, 'sampler_2ndname': secondSampler?['user_name'], 'sample_date': samplingDate, 'sample_time': samplingTime, 'sample_state': selectedStateName, 'station_id': selectedStation?['tbl_station_code'], 'station_latitude': stationLatitude, 'station_longitude': stationLongitude, 'latitude': currentLatitude, 'longitude': currentLongitude, 'sample_id': reportId, // Using reportId as a unique identifier for the sample. }; } /// Creates a JSON object for sensor readings, mimicking 'reading.json'. Map toReadingJson() { return { 'classification': selectedClassification?['classification_name'], 'classification_id': classificationId, 'optional_remark_1': optionalRemark1, 'optional_remark_2': optionalRemark2, 'optional_remark_3': optionalRemark3, 'optional_remark_4': optionalRemark4, 'distance_difference': distanceDifference, 'distance_difference_remarks': distanceDifferenceRemarks, }; } /// Creates a JSON object for manual info, mimicking 'manual_info.json'. Map toManualInfoJson() { return { // Tarball forms don't have a specific 'weather' or general remarks field, // so we use the distance remarks as a stand-in if available. 'remarks_event': distanceDifferenceRemarks, 'remarks_lab': null, }; } }