// lib/screens/marine/manual/marine_manual_data_status_log.dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:environment_monitoring_app/auth_provider.dart';
import 'package:environment_monitoring_app/models/tarball_data.dart';
import 'package:environment_monitoring_app/models/in_situ_sampling_data.dart';
import 'package:environment_monitoring_app/services/local_storage_service.dart';
import 'package:environment_monitoring_app/services/api_service.dart';
// START CHANGE: Import the new dedicated services
import 'package:environment_monitoring_app/services/marine_in_situ_sampling_service.dart';
import 'package:environment_monitoring_app/services/marine_tarball_sampling_service.dart';
// END CHANGE
import 'dart:convert';

// --- START: ADDED HELPER CLASS ---
/// A simple class to hold an image file and its associated remark.
class ImageLogEntry {
  final File file;
  final String? remark;
  ImageLogEntry({required this.file, this.remark});
}
// --- END: ADDED HELPER CLASS ---


class SubmissionLogEntry {
  final String type;
  final String title;
  final String stationCode;
  final DateTime submissionDateTime;
  final String? reportId;
  final String status;
  final String message;
  final Map<String, dynamic> rawData;
  final String serverName;
  final String? apiStatusRaw;
  final String? ftpStatusRaw;
  bool isResubmitting;

  SubmissionLogEntry({
    required this.type,
    required this.title,
    required this.stationCode,
    required this.submissionDateTime,
    this.reportId,
    required this.status,
    required this.message,
    required this.rawData,
    required this.serverName,
    this.apiStatusRaw,
    this.ftpStatusRaw,
    this.isResubmitting = false,
  });
}

class MarineManualDataStatusLog extends StatefulWidget {
  const MarineManualDataStatusLog({super.key});

  @override
  State<MarineManualDataStatusLog> createState() => _MarineManualDataStatusLogState();
}

class _MarineManualDataStatusLogState extends State<MarineManualDataStatusLog> {
  final LocalStorageService _localStorageService = LocalStorageService();
  // MODIFIED: Declare the service variables but do not instantiate them here.
  late MarineInSituSamplingService _marineInSituService;
  late MarineTarballSamplingService _marineTarballService;

  List<SubmissionLogEntry> _manualLogs = [];
  List<SubmissionLogEntry> _tarballLogs = [];
  List<SubmissionLogEntry> _filteredManualLogs = [];
  List<SubmissionLogEntry> _filteredTarballLogs = [];

  final TextEditingController _manualSearchController = TextEditingController();
  final TextEditingController _tarballSearchController = TextEditingController();

  bool _isLoading = true;
  final Map<String, bool> _isResubmitting = {};

  @override
  void initState() {
    super.initState();
    // MODIFIED: Service instantiations are removed from initState.
    // They will be initialized in didChangeDependencies.
    _manualSearchController.addListener(_filterLogs);
    _tarballSearchController.addListener(_filterLogs);
    _loadAllLogs();
  }

  // ADDED: didChangeDependencies to safely get services from the Provider.
  // This is the correct lifecycle method for this purpose.
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // Fetch the single, global instances of the services from the Provider tree.
    // --- START FIX: Added listen: false to prevent unnecessary rebuilds ---
    _marineInSituService = Provider.of<MarineInSituSamplingService>(context, listen: false);
    _marineTarballService = Provider.of<MarineTarballSamplingService>(context, listen: false);
    // --- END FIX ---
  }

  @override
  void dispose() {
    _manualSearchController.dispose();
    _tarballSearchController.dispose();
    super.dispose();
  }

  Future<void> _loadAllLogs() async {
    setState(() => _isLoading = true);

    final tarballLogs = await _localStorageService.getAllTarballLogs();
    final inSituLogs = await _localStorageService.getAllInSituLogs();

    final List<SubmissionLogEntry> tempManual = [];
    final List<SubmissionLogEntry> tempTarball = [];

    for (var log in inSituLogs) {
      // START FIX: Use backward-compatible keys to read the timestamp
      final String dateStr = log['sampling_date'] ?? log['man_date'] ?? '';
      final String timeStr = log['sampling_time'] ?? log['man_time'] ?? '';
      // END FIX

      // --- START FIX: Prevent fallback to DateTime.now() to make errors visible ---
      final dt = DateTime.tryParse('$dateStr $timeStr');
      // --- END FIX ---

      tempManual.add(SubmissionLogEntry(
        type: 'Manual Sampling',
        title: log['selectedStation']?['man_station_name'] ?? 'Unknown Station',
        stationCode: log['selectedStation']?['man_station_code'] ?? 'N/A',
        // --- START FIX: Use the parsed date or a placeholder for invalid entries ---
        submissionDateTime: dt ?? DateTime.fromMillisecondsSinceEpoch(0),
        // --- END FIX ---
        reportId: log['reportId']?.toString(),
        status: log['submissionStatus'] ?? 'L1',
        message: log['submissionMessage'] ?? 'No status message.',
        rawData: log,
        serverName: log['serverConfigName'] ?? 'Unknown Server',
        apiStatusRaw: log['api_status'],
        ftpStatusRaw: log['ftp_status'],
      ));
    }

    for (var log in tarballLogs) {
      final dateStr = log['sampling_date'] ?? '';
      final timeStr = log['sampling_time'] ?? '';

      tempTarball.add(SubmissionLogEntry(
        type: 'Tarball Sampling',
        title: log['selectedStation']?['tbl_station_name'] ?? 'Unknown Station',
        stationCode: log['selectedStation']?['tbl_station_code'] ?? 'N/A',
        submissionDateTime: DateTime.tryParse('$dateStr $timeStr') ?? DateTime.fromMillisecondsSinceEpoch(0),
        reportId: log['reportId']?.toString(),
        status: log['submissionStatus'] ?? 'L1',
        message: log['submissionMessage'] ?? 'No status message.',
        rawData: log,
        serverName: log['serverConfigName'] ?? 'Unknown Server',
        apiStatusRaw: log['api_status'],
        ftpStatusRaw: log['ftp_status'],
      ));
    }

    tempManual.sort((a, b) => b.submissionDateTime.compareTo(a.submissionDateTime));
    tempTarball.sort((a, b) => b.submissionDateTime.compareTo(a.submissionDateTime));

    if (mounted) {
      setState(() {
        _manualLogs = tempManual;
        _tarballLogs = tempTarball;
        _isLoading = false;
      });
      _filterLogs();
    }
  }

  void _filterLogs() {
    final manualQuery = _manualSearchController.text.toLowerCase();
    final tarballQuery = _tarballSearchController.text.toLowerCase();

    setState(() {
      _filteredManualLogs = _manualLogs.where((log) => _logMatchesQuery(log, manualQuery)).toList();
      _filteredTarballLogs = _tarballLogs.where((log) => _logMatchesQuery(log, tarballQuery)).toList();
    });
  }

  bool _logMatchesQuery(SubmissionLogEntry log, String query) {
    if (query.isEmpty) return true;
    return log.title.toLowerCase().contains(query) ||
        log.stationCode.toLowerCase().contains(query) ||
        log.serverName.toLowerCase().contains(query) ||
        (log.reportId?.toLowerCase() ?? '').contains(query);
  }

  File? _createFileFromPath(String? path) {
    if (path != null && path.isNotEmpty) {
      return File(path);
    }
    return null;
  }

  Future<void> _resubmitData(SubmissionLogEntry log) async {
    final logKey = log.reportId ?? log.submissionDateTime.toIso8601String();
    if (mounted) {
      setState(() {
        _isResubmitting[logKey] = true;
      });
    }

    try {
      final authProvider = Provider.of<AuthProvider>(context, listen: false);
      final appSettings = authProvider.appSettings;

      Map<String, dynamic> result = {};

      if (log.type == 'Manual Sampling') {
        // --- START FIX: Rely on the now-robust fromJson factory for cleaner reconstruction ---
        final dataToResubmit = InSituSamplingData.fromJson(log.rawData);
        // --- END FIX ---

        result = await _marineInSituService.submitInSituSample(
          data: dataToResubmit,
          appSettings: appSettings,
          context: context,
          authProvider: authProvider,
          logDirectory: log.rawData['logDirectory'] as String?,
        );
      } else if (log.type == 'Tarball Sampling') {
        final dataToResubmit = TarballSamplingData();
        final logData = log.rawData;

        dataToResubmit.firstSampler = logData['first_sampler_name'];
        dataToResubmit.firstSamplerUserId = int.tryParse(logData['first_sampler_user_id']?.toString() ?? '');
        dataToResubmit.secondSampler = logData['secondSampler'];
        dataToResubmit.samplingDate = logData['sampling_date'];
        dataToResubmit.samplingTime = logData['sampling_time'];
        dataToResubmit.selectedStateName = logData['selectedStation']?['state_name'];
        dataToResubmit.selectedCategoryName = logData['selectedStation']?['category_name'];
        dataToResubmit.selectedStation = logData['selectedStation'];
        dataToResubmit.stationLatitude = logData['selectedStation']?['tbl_latitude']?.toString();
        dataToResubmit.stationLongitude = logData['selectedStation']?['tbl_longitude']?.toString();
        dataToResubmit.currentLatitude = logData['current_latitude'];
        dataToResubmit.currentLongitude = logData['current_longitude'];
        dataToResubmit.distanceDifference = double.tryParse(logData['distance_difference']?.toString() ?? '');
        dataToResubmit.distanceDifferenceRemarks = logData['distance_remarks'];
        dataToResubmit.classificationId = int.tryParse(logData['classification_id']?.toString() ?? '');
        dataToResubmit.selectedClassification = logData['selectedClassification'];
        dataToResubmit.optionalRemark1 = logData['optional_photo_remark_01'];
        dataToResubmit.optionalRemark2 = logData['optional_photo_remark_02'];
        dataToResubmit.optionalRemark3 = logData['optional_photo_remark_03'];
        dataToResubmit.optionalRemark4 = logData['optional_photo_remark_04'];
        dataToResubmit.leftCoastalViewImage = _createFileFromPath(logData['left_side_coastal_view']);
        dataToResubmit.rightCoastalViewImage = _createFileFromPath(logData['right_side_coastal_view']);
        dataToResubmit.verticalLinesImage = _createFileFromPath(logData['drawing_vertical_lines']);
        dataToResubmit.horizontalLineImage = _createFileFromPath(logData['drawing_horizontal_line']);
        dataToResubmit.optionalImage1 = _createFileFromPath(logData['optional_photo_01']);
        dataToResubmit.optionalImage2 = _createFileFromPath(logData['optional_photo_02']);
        dataToResubmit.optionalImage3 = _createFileFromPath(logData['optional_photo_03']);
        dataToResubmit.optionalImage4 = _createFileFromPath(logData['optional_photo_04']);

        result = await _marineTarballService.submitTarballSample(
          data: dataToResubmit,
          appSettings: appSettings,
          context: context,
        );
      }

      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text(result['message'] ?? 'Resubmission process completed.')),
        );
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Resubmission failed: $e')),
        );
      }
    } finally {
      if (mounted) {
        setState(() {
          _isResubmitting.remove(logKey);
        });
        _loadAllLogs();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final hasAnyLogs = _manualLogs.isNotEmpty || _tarballLogs.isNotEmpty;

    return Scaffold(
      appBar: AppBar(title: const Text('Marine Manual Data Status Log')),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : RefreshIndicator(
        onRefresh: _loadAllLogs,
        child: !hasAnyLogs
            ? const Center(child: Text('No submission logs found.'))
            : ListView(
          padding: const EdgeInsets.all(8.0),
          children: [
            _buildCategorySection('Manual Sampling', _filteredManualLogs, _manualSearchController),
            _buildCategorySection('Tarball Sampling', _filteredTarballLogs, _tarballSearchController),
          ],
        ),
      ),
    );
  }

  Widget _buildCategorySection(String category, List<SubmissionLogEntry> logs, TextEditingController searchController) {
    return Card(
      margin: const EdgeInsets.symmetric(vertical: 8.0),
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(category, style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold)),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: TextField(
                controller: searchController,
                decoration: InputDecoration(
                  hintText: 'Search in $category...',
                  prefixIcon: const Icon(Icons.search, size: 20),
                  isDense: true,
                  border: const OutlineInputBorder(),
                  suffixIcon: searchController.text.isNotEmpty ? IconButton(
                    icon: const Icon(Icons.clear),
                    onPressed: () {
                      searchController.clear();
                    },
                  ) : null,
                ),
              ),
            ),
            const Divider(),
            if (logs.isEmpty)
              const Padding(
                  padding: EdgeInsets.all(16.0),
                  child: Center(child: Text('No logs match your search in this category.')))
            else
              ListView.builder(
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                itemCount: logs.length,
                itemBuilder: (context, index) {
                  return _buildLogListItem(logs[index]);
                },
              ),
          ],
        ),
      ),
    );
  }

  Widget _buildLogListItem(SubmissionLogEntry log) {
    final logKey = log.reportId ?? log.submissionDateTime.toIso8601String();
    final isResubmitting = _isResubmitting[logKey] ?? false;

    // --- START: MODIFICATION FOR GRANULAR STATUS ICONS ---
    // Define the different states based on the detailed status code.
    final bool isFullSuccess = log.status == 'S4';
    final bool isPartialSuccess = log.status == 'S3' || log.status == 'L4';
    final bool canResubmit = !isFullSuccess; // Allow resubmission for partial success or failure.

    // Determine the icon and color based on the state.
    IconData statusIcon;
    Color statusColor;

    if (isFullSuccess) {
      statusIcon = Icons.check_circle_outline;
      statusColor = Colors.green;
    } else if (isPartialSuccess) {
      statusIcon = Icons.warning_amber_rounded;
      statusColor = Colors.orange;
    } else {
      statusIcon = Icons.error_outline;
      statusColor = Colors.red;
    }
    // --- END: MODIFICATION FOR GRANULAR STATUS ICONS ---

    final titleWidget = RichText(
      text: TextSpan(
        style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500),
        children: <TextSpan>[
          TextSpan(text: '${log.title} '),
          TextSpan(
            text: '(${log.stationCode})',
            style: Theme.of(context).textTheme.bodySmall?.copyWith(fontWeight: FontWeight.normal),
          ),
        ],
      ),
    );

    final bool isDateValid = !log.submissionDateTime.isAtSameMomentAs(DateTime.fromMillisecondsSinceEpoch(0));
    final subtitle = isDateValid
        ? '${log.serverName} - ${DateFormat('yyyy-MM-dd HH:mm').format(log.submissionDateTime)}'
        : '${log.serverName} - Invalid Date';

    return ExpansionTile(
      key: PageStorageKey(logKey),
      leading: Icon(statusIcon, color: statusColor),
      title: titleWidget,
      subtitle: Text(subtitle),
      trailing: canResubmit
          ? (isResubmitting
          ? const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(strokeWidth: 3))
          : IconButton(icon: const Icon(Icons.sync, color: Colors.blue), tooltip: 'Resubmit', onPressed: () => _resubmitData(log)))
          : null,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildDetailRow('High-Level Status:', log.status),
              _buildDetailRow('Server:', log.serverName),
              _buildDetailRow('Report ID:', log.reportId ?? 'N/A'),
              _buildDetailRow('Submission Type:', log.type),

              // --- START: ADDED BUTTONS AND GRANULAR STATUS ---
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    TextButton.icon(
                      icon: Icon(Icons.list_alt, color: Theme.of(context).colorScheme.primary),
                      label: Text('View Data', style: TextStyle(color: Theme.of(context).colorScheme.primary)),
                      onPressed: () => _showDataDialog(context, log),
                    ),
                    TextButton.icon(
                      icon: Icon(Icons.photo_library_outlined, color: Theme.of(context).colorScheme.secondary),
                      label: Text('View Images', style: TextStyle(color: Theme.of(context).colorScheme.secondary)),
                      onPressed: () => _showImageDialog(context, log),
                    ),
                  ],
                ),
              ),
              const Divider(height: 10),
              _buildGranularStatus('API', log.apiStatusRaw),
              _buildGranularStatus('FTP', log.ftpStatusRaw),
              // --- END: ADDED BUTTONS AND GRANULAR STATUS ---
            ],
          ),
        )
      ],
    );
  }

  Widget _buildDetailRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Expanded(flex: 2, child: Text(label, style: const TextStyle(fontWeight: FontWeight.bold))),
          const SizedBox(width: 8),
          Expanded(flex: 3, child: Text(value)),
        ],
      ),
    );
  }

  // =========================================================================
  // --- START: ADDED METHODS FOR VIEW DATA / VIEW IMAGE FUNCTIONALITY ---
  // =========================================================================

  /// Builds a formatted category header row for the data table.
  TableRow _buildCategoryRow(BuildContext context, String title, IconData icon) {
    return TableRow(
      decoration: BoxDecoration(
        color: Colors.grey.shade100,
      ),
      children: [
        Padding(
          padding: const EdgeInsets.only(top: 16.0, bottom: 8.0, left: 8.0, right: 8.0),
          child: Row(
            children: [
              Icon(icon, size: 20, color: Theme.of(context).primaryColor),
              const SizedBox(width: 8),
              Text(
                title,
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 14,
                  color: Theme.of(context).primaryColor,
                ),
              ),
            ],
          ),
        ),
        const SizedBox.shrink(), // Empty cell for the second column
      ],
    );
  }

  /// Builds a formatted row for the data dialog, gracefully handling null/empty values.
  TableRow _buildDataTableRow(String label, String? value) {
    String displayValue = (value == null || value.isEmpty || value == 'null') ? 'N/A' : value;

    // Format special "missing" values
    if (displayValue == '-999.0' || displayValue == '-999') {
      displayValue = 'N/A';
    }

    return TableRow(
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
          // --- START: MODIFICATION FOR FONT SIZE ---
          child: Text(
            label,
            style: const TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 11.0, // <-- ADJUST THIS VALUE AS NEEDED
            ),
          ),
          // --- END: MODIFICATION FOR FONT SIZE ---
        ),
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
          // --- START: MODIFICATION FOR FONT SIZE ---
          child: Text(
            displayValue,
            style: const TextStyle(fontSize: 11.0), // <-- ADJUST THIS VALUE AS NEEDED
          ),
          // --- END: MODIFICATION FOR FONT SIZE ---
        ),
      ],
    );
  }

  /// Helper to safely get a string value from the raw data map.
  String? _getString(Map<String, dynamic> data, String key) {
    final value = data[key];
    if (value == null) return null;
    if (value is double && value == -999.0) return 'N/A';
    return value.toString();
  }

  /// Shows the categorized and formatted data log in a dialog
  void _showDataDialog(BuildContext context, SubmissionLogEntry log) {
    final Map<String, dynamic> data = log.rawData;
    final List<TableRow> tableRows = [];

    // --- 1. Sampling Info ---
    tableRows.add(_buildCategoryRow(context, 'Sampling Info', Icons.calendar_today));
    tableRows.add(_buildDataTableRow('Date', _getString(data, 'sampling_date') ?? _getString(data, 'man_date') ?? _getString(data, 'eventDate')));
    tableRows.add(_buildDataTableRow('Time', _getString(data, 'sampling_time') ?? _getString(data, 'man_time') ?? _getString(data, 'eventTime')));

    String? firstSamplerName = _getString(data, 'first_sampler_name') ?? _getString(data, 'firstSampler');
    tableRows.add(_buildDataTableRow('1st Sampler', firstSamplerName));

    String? secondSamplerName;
    if (data['secondSampler'] is Map) {
      secondSamplerName = (data['secondSampler'] as Map)['first_name']?.toString();
    }
    tableRows.add(_buildDataTableRow('2nd Sampler', secondSamplerName));
    tableRows.add(_buildDataTableRow('Sample ID', _getString(data, 'sample_id_code') ?? _getString(data, 'sampleIdCode'))); // For In-Situ

    // --- 2. Station & Location ---
    tableRows.add(_buildCategoryRow(context, 'Station & Location', Icons.location_on_outlined));
    tableRows.add(_buildDataTableRow('Station', '${log.stationCode} - ${log.title}'));

    String? stationLat;
    String? stationLon;
    if (data['selectedStation'] is Map) {
      final stationMap = data['selectedStation'] as Map<String, dynamic>;
      stationLat = _getString(stationMap, 'man_latitude') ?? _getString(stationMap, 'tbl_latitude');
      stationLon = _getString(stationMap, 'man_longitude') ?? _getString(stationMap, 'tbl_longitude');
    }
    tableRows.add(_buildDataTableRow('Station Latitude', stationLat));
    tableRows.add(_buildDataTableRow('Station Longitude', stationLon));

    tableRows.add(_buildDataTableRow('Current Latitude', _getString(data, 'current_latitude') ?? _getString(data, 'currentLatitude') ?? _getString(data, 'latitude')));
    tableRows.add(_buildDataTableRow('Current Longitude', _getString(data, 'current_longitude') ?? _getString(data, 'currentLongitude') ?? _getString(data, 'longitude')));

    tableRows.add(_buildDataTableRow('Distance (km)', _getString(data, 'distance_difference') ?? _getString(data, 'distanceDifferenceInKm') ?? _getString(data, 'distance_difference_in_km')));
    tableRows.add(_buildDataTableRow('Distance Remarks', _getString(data, 'distance_remarks') ?? _getString(data, 'distanceDifferenceRemarks') ?? _getString(data, 'distance_difference_remarks')));

    // --- 3. Site Conditions (In-Situ or NPE) ---
    if (log.type == 'Manual Sampling' || log.type == 'NPE Report') {
      tableRows.add(_buildCategoryRow(context, 'Site Conditions', Icons.wb_sunny_outlined));
      tableRows.add(_buildDataTableRow('Tide', _getString(data, 'tide_level') ?? _getString(data, 'tideLevel') ?? _getString(data, 'tide_level_manual')));
      tableRows.add(_buildDataTableRow('Sea', _getString(data, 'sea_condition') ?? _getString(data, 'seaCondition') ?? _getString(data, 'sea_condition_manual')));
      tableRows.add(_buildDataTableRow('Weather', _getString(data, 'weather') ?? _getString(data, 'weather_manual')));

      tableRows.add(_buildDataTableRow('Event Remarks', _getString(data, 'event_remarks') ?? _getString(data, 'man_event_remark') ?? _getString(data, 'eventRemark')));
      tableRows.add(_buildDataTableRow('Lab Remarks', _getString(data, 'lab_remarks') ?? _getString(data, 'man_lab_remark') ?? _getString(data, 'labRemark')));
    }

    // --- 4. Tarball Classification (Tarball only) ---
    if (log.type == 'Tarball Sampling') {
      tableRows.add(_buildCategoryRow(context, 'Classification', Icons.category_outlined));
      String? classification = "N/A";
      if (data['selectedClassification'] is Map) {
        classification = (data['selectedClassification'] as Map)['classification_name']?.toString();
      }
      tableRows.add(_buildDataTableRow('Classification', classification));
    }

    // --- 5. Parameters (In-Situ or NPE) ---
    if (log.type == 'Manual Sampling' || log.type == 'NPE Report') {
      tableRows.add(_buildCategoryRow(context, 'Parameters', Icons.bar_chart));
      tableRows.add(_buildDataTableRow('Sonde ID', _getString(data, 'sonde_id') ?? _getString(data, 'sondeId')));
      tableRows.add(_buildDataTableRow('Capture Date', _getString(data, 'data_capture_date') ?? _getString(data, 'dataCaptureDate')));
      tableRows.add(_buildDataTableRow('Capture Time', _getString(data, 'data_capture_time') ?? _getString(data, 'dataCaptureTime')));
      tableRows.add(_buildDataTableRow('Oxygen Conc (mg/L)', _getString(data, 'oxygen_concentration') ?? _getString(data, 'oxygenConcentration')));
      tableRows.add(_buildDataTableRow('Oxygen Sat (%)', _getString(data, 'oxygen_saturation') ?? _getString(data, 'oxygenSaturation')));
      tableRows.add(_buildDataTableRow('pH', _getString(data, 'ph')));
      tableRows.add(_buildDataTableRow('Salinity (ppt)', _getString(data, 'salinity')));
      tableRows.add(_buildDataTableRow('Conductivity (µS/cm)', _getString(data, 'electrical_conductivity') ?? _getString(data, 'electricalConductivity')));
      tableRows.add(_buildDataTableRow('Temperature (°C)', _getString(data, 'temperature')));
      tableRows.add(_buildDataTableRow('TDS (mg/L)', _getString(data, 'tds')));
      tableRows.add(_buildDataTableRow('Turbidity (NTU)', _getString(data, 'turbidity')));
      tableRows.add(_buildDataTableRow('Battery (V)', _getString(data, 'battery_voltage') ?? _getString(data, 'batteryVoltage')));
    }

    // --- 6. NPE Specific Fields ---
    if (log.type == 'NPE Report') {
      tableRows.add(_buildCategoryRow(context, 'NPE Details', Icons.warning_amber_rounded));
      tableRows.add(_buildDataTableRow('Possible Source', _getString(data, 'possibleSource')));
      tableRows.add(_buildDataTableRow('Other Remarks', _getString(data, 'othersObservationRemark')));

      if(data['fieldObservations'] is Map) {
        final observations = data['fieldObservations'] as Map<String, dynamic>;
        String obsText = observations.entries
            .where((e) => e.value == true)
            .map((e) => e.key)
            .join(', ');
        tableRows.add(_buildDataTableRow('Observations', obsText.isEmpty ? 'N/A' : obsText));
      }
    }

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text('${log.stationCode} - ${log.title}'),
          content: SizedBox(
            width: double.maxFinite,
            child: SingleChildScrollView(
              child: Table(
                columnWidths: const {
                  0: IntrinsicColumnWidth(),
                  1: FlexColumnWidth(),
                },
                border: TableBorder(
                  horizontalInside: BorderSide(
                    color: Colors.grey.shade300,
                    width: 0.5,
                  ),
                ),
                children: tableRows,
              ),
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Close'),
            ),
          ],
        );
      },
    );
  }

  /// Shows the image gallery dialog
  void _showImageDialog(BuildContext context, SubmissionLogEntry log) {

    final List<ImageLogEntry> imageEntries = [];

    if (log.type == 'Manual Sampling') {
      // In-Situ Image Keys
      const imageRemarkMap = {
        'man_left_side_land_view': null,
        'man_right_side_land_view': null,
        'man_filling_water_into_sample_bottle': null,
        'man_seawater_in_clear_glass_bottle': null,
        'man_examine_preservative_ph_paper': null,
        'man_optional_photo_01': 'man_optional_photo_01_remarks',
        'man_optional_photo_02': 'man_optional_photo_02_remarks',
        'man_optional_photo_03': 'man_optional_photo_03_remarks',
        'man_optional_photo_04': 'man_optional_photo_04_remarks',
      };
      _addImagesToList(log, imageRemarkMap, imageEntries);

    } else if (log.type == 'Tarball Sampling') {
      // Tarball Image Keys
      const imageRemarkMap = {
        'left_side_coastal_view': null,
        'right_side_coastal_view': null,
        'drawing_vertical_lines': null,
        'drawing_horizontal_line': null,
        'optional_photo_01': 'optional_photo_remark_01',
        'optional_photo_02': 'optional_photo_remark_02',
        'optional_photo_03': 'optional_photo_remark_03',
        'optional_photo_04': 'optional_photo_remark_04',
      };
      _addImagesToList(log, imageRemarkMap, imageEntries);

    } else if (log.type == 'NPE Report') {
      // NPE Image Keys (remarks not stored in log)
      const imageRemarkMap = {
        'image1': null,
        'image2': null,
        'image3': null,
        'image4': null,
      };
      _addImagesToList(log, imageRemarkMap, imageEntries);
    }


    if (imageEntries.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('No images are attached to this log.'),
          backgroundColor: Colors.orange,
        ),
      );
      return;
    }

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text('Images for ${log.stationCode} - ${log.title}'),
          content: SizedBox(
            width: double.maxFinite,
            child: GridView.builder(
              shrinkWrap: true,
              itemCount: imageEntries.length,
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
              ),
              itemBuilder: (context, index) {
                final imageEntry = imageEntries[index];
                final bool hasRemark = imageEntry.remark != null && imageEntry.remark!.isNotEmpty;

                return Card(
                  clipBehavior: Clip.antiAlias,
                  elevation: 2,
                  child: Stack(
                    fit: StackFit.expand,
                    children: [
                      Image.file(
                        imageEntry.file,
                        fit: BoxFit.cover,
                        errorBuilder: (context, error, stack) {
                          return const Center(
                            child: Icon(
                              Icons.broken_image,
                              color: Colors.grey,
                              size: 40,
                            ),
                          );
                        },
                      ),
                      if (hasRemark)
                        Positioned(
                          bottom: 0,
                          left: 0,
                          right: 0,
                          child: Container(
                            padding: const EdgeInsets.all(6.0),
                            decoration: BoxDecoration(
                              gradient: LinearGradient(
                                begin: Alignment.bottomCenter,
                                end: Alignment.topCenter,
                                colors: [
                                  Colors.black.withOpacity(0.8),
                                  Colors.black.withOpacity(0.0)
                                ],
                              ),
                            ),
                            child: Text(
                              imageEntry.remark!,
                              style: const TextStyle(
                                color: Colors.white,
                                fontSize: 12,
                                fontWeight: FontWeight.bold,
                              ),
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                        ),
                    ],
                  ),
                );
              },
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Close'),
            ),
          ],
        );
      },
    );
  }

  // --- START: NEW HELPER for _showImageDialog ---
  void _addImagesToList(SubmissionLogEntry log, Map<String, String?> imageRemarkMap, List<ImageLogEntry> imageEntries) {
    for (final entry in imageRemarkMap.entries) {
      final imageKey = entry.key;
      final remarkKey = entry.value;

      final path = log.rawData[imageKey];
      if (path != null && path is String && path.isNotEmpty) {
        final file = File(path);
        if (file.existsSync()) {
          final remark = (remarkKey != null ? log.rawData[remarkKey] as String? : null);
          imageEntries.add(ImageLogEntry(file: file, remark: remark));
        }
      }
    }
  }

  Widget _buildGranularStatus(String type, String? jsonStatus) {
    if (jsonStatus == null || jsonStatus.isEmpty) {
      return Container();
    }

    List<dynamic> statuses;
    try {
      statuses = jsonDecode(jsonStatus);
    } catch (_) {
      return _buildDetailRow('$type Status:', jsonStatus);
    }

    if (statuses.isEmpty) {
      return Container();
    }

    return Padding(
      padding: const EdgeInsets.only(top: 8.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('$type Status:', style: const TextStyle(fontWeight: FontWeight.bold)),
          ...statuses.map((s) {
            final serverName = s['server_name'] ?? s['config_name'] ?? 'Server N/A';
            final status = s['message'] ?? 'N/A';
            final bool isSuccess = s['success'] as bool? ?? false;
            final IconData icon = isSuccess ? Icons.check_circle_outline : Icons.error_outline;
            final Color color = isSuccess ? Colors.green : Colors.red;
            String detailLabel = (s['type'] != null) ? '(${s['type']})' : '';

            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 8.0),
              child: Row(
                children: [
                  Icon(icon, size: 16, color: color),
                  const SizedBox(width: 5),
                  Expanded(child: Text('$serverName $detailLabel: $status')),
                ],
              ),
            );
          }).toList(),
        ],
      ),
    );
  }
// =========================================================================
// --- END: ADDED METHODS FOR VIEW DATA / VIEW IMAGE FUNCTIONALITY ---
// =========================================================================
}