// lib/services/local_storage_service.dart

import 'dart:io';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path/path.dart' as p;
import 'package:dio/dio.dart';
import 'package:geolocator/geolocator.dart';

import '../models/air_installation_data.dart';
import '../models/air_collection_data.dart';
import '../models/tarball_data.dart';
import '../models/in_situ_sampling_data.dart';
import '../models/marine_manual_npe_report_data.dart';
// --- ADDED: Imports for new data models ---
import '../models/marine_manual_pre_departure_checklist_data.dart';
import '../models/marine_manual_sonde_calibration_data.dart';
import '../models/marine_manual_equipment_maintenance_data.dart';
// --- END ADDED ---
import '../models/river_in_situ_sampling_data.dart';
import '../models/river_manual_triennial_sampling_data.dart';
// --- ADDED IMPORT ---
import '../models/marine_inves_manual_sampling_data.dart';
// --- ADDED IMPORT FOR RIVER INVESTIGATIVE ---
import '../models/river_inves_manual_sampling_data.dart';
// --- END ADDED IMPORT ---

class LocalStorageService {

  // =======================================================================
  // Part 1: Public Storage Setup
  // =======================================================================

  Future<bool> _requestPermissions() async {
    var status = await Permission.manageExternalStorage.request();
    return status.isGranted;
  }

  Future<Directory?> _getPublicMMSV4Directory({required String serverName}) async {
    if (await _requestPermissions()) {
      final Directory? externalDir = await getExternalStorageDirectory();
      if (externalDir != null) {
        final publicRootPath = externalDir.path.split('/Android/')[0];
        final mmsv4Dir = Directory(p.join(publicRootPath, 'MMSV4', serverName));
        if (!await mmsv4Dir.exists()) {
          await mmsv4Dir.create(recursive: true);
        }
        return mmsv4Dir;
      }
    }
    debugPrint("LocalStorageService: Manage External Storage permission was not granted.");
    return null;
  }

  Future<Directory?> getLogDirectory({required String serverName, required String module, required String subModule}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;
    final logDir = Directory(p.join(mmsv4Dir.path, module, subModule));
    if (!await logDir.exists()) {
      await logDir.create(recursive: true);
    }
    return logDir;
  }

  // =======================================================================
  // Part 2: Air Manual Sampling Methods (LOGGING RESTORED)
  // =======================================================================

  Future<Directory?> _getAirManualBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final airDir = Directory(p.join(mmsv4Dir.path, 'air', 'air_manual_sampling'));
    if (!await airDir.exists()) {
      await airDir.create(recursive: true);
    }
    return airDir;
  }

  Future<String?> saveAirSamplingRecord(Map<String, dynamic> data, String refID, {required String serverName}) async {
    final baseDir = await _getAirManualBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for Air Manual. Check permissions.");
      return null;
    }

    try {
      final eventDir = Directory(p.join(baseDir.path, refID));
      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      Future<String?> copyImageToLocal(dynamic imageFile) async {
        if (imageFile is! File) return null;
        try {
          if (p.dirname(imageFile.path) == eventDir.path) {
            return imageFile.path;
          }
          final String fileName = p.basename(imageFile.path);
          final File newFile = await imageFile.copy(p.join(eventDir.path, fileName));
          return newFile.path;
        } catch (e) {
          debugPrint("Error copying file ${imageFile.path}: $e");
          return null;
        }
      }

      final Map<String, dynamic> serializableData = Map.from(data);
      serializableData['serverConfigName'] = serverName;

      final installationImageKeys = ['imageFront', 'imageBack', 'imageLeft', 'imageRight', 'optionalImage1', 'optionalImage2', 'optionalImage3', 'optionalImage4'];

      for (final key in installationImageKeys) {
        if (serializableData.containsKey(key) && serializableData[key] is File) {
          final newPath = await copyImageToLocal(serializableData[key]);
          serializableData['${key}Path'] = newPath;
        }
      }

      if (serializableData['collectionData'] is Map) {
        final collectionMap = Map<String, dynamic>.from(serializableData['collectionData']);
        final collectionImageKeys = ['imageFront', 'imageBack', 'imageLeft', 'imageRight', 'imageChart', 'imageFilterPaper', 'optionalImage1', 'optionalImage2', 'optionalImage3', 'optionalImage4'];

        for (final key in collectionImageKeys) {
          if (collectionMap.containsKey(key) && collectionMap[key] is File) {
            final newPath = await copyImageToLocal(collectionMap[key]);
            collectionMap['${key}Path'] = newPath;
          }
        }
        serializableData['collectionData'] = collectionMap;
      }

      final Map<String, dynamic> finalData = Map.from(serializableData);

      void cleanMap(Map<String, dynamic> map) {
        map.removeWhere((key, value) => value is File);
        map.forEach((key, value) {
          if (value is Map) cleanMap(value as Map<String, dynamic>);
        });
      }

      cleanMap(finalData);

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(finalData));
      debugPrint("Air sampling log and images saved to: ${eventDir.path}");

      return eventDir.path;

    } catch (e, s) {
      debugPrint("Error saving air sampling log to local storage: $e");
      debugPrint("Stack trace: $s");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllAirSamplingLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'air', 'air_manual_sampling'));
      if (!await baseDir.exists()) continue;

      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading air logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  // =======================================================================
  // Part 3: Tarball Specific Methods (LOGGING RESTORED)
  // =======================================================================

  Future<Directory?> _getTarballBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final tarballDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_tarball_sampling'));
    if (!await tarballDir.exists()) {
      await tarballDir.create(recursive: true);
    }
    return tarballDir;
  }

  Future<String?> saveTarballSamplingData(TarballSamplingData data, {required String serverName}) async {
    final baseDir = await _getTarballBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.selectedStation?['tbl_station_code'] ?? 'UNKNOWN_STATION';
      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      final Map<String, dynamic> jsonData = { ...data.toFormData(), 'submissionStatus': data.submissionStatus, 'submissionMessage': data.submissionMessage, 'reportId': data.reportId };
      jsonData['serverConfigName'] = serverName;
      jsonData['selectedStation'] = data.selectedStation;

      jsonData['selectedClassification'] = data.selectedClassification;
      jsonData['secondSampler'] = data.secondSampler;

      final imageFiles = data.toImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null && imageFile.path.isNotEmpty) {
          try {
            if (p.dirname(imageFile.path) == eventDir.path) {
              jsonData[entry.key] = imageFile.path;
            } else {
              final String originalFileName = p.basename(imageFile.path);
              final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
              jsonData[entry.key] = newFile.path;
            }
          } catch (e) {
            debugPrint("Error processing image file ${imageFile.path}: $e");
            jsonData[entry.key] = null;
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("Tarball log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving tarball log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllTarballLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_tarball_sampling'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading tarball logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateTarballLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("Log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating tarball log: $e");
    }
  }

  // =======================================================================
  // Part 4: Marine In-Situ Specific Methods (LOGGING RESTORED)
  // =======================================================================

  Future<Directory?> getInSituBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final inSituDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_in_situ_sampling'));
    if (!await inSituDir.exists()) {
      await inSituDir.create(recursive: true);
    }
    return inSituDir;
  }

  Future<String?> saveInSituSamplingData(InSituSamplingData data, {required String serverName}) async {
    final baseDir = await getInSituBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for In-Situ. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.selectedStation?['man_station_code'] ?? 'UNKNOWN_STATION';
      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      // --- START: MODIFICATION (FIXED ERROR) ---
      // This line is CORRECT. It uses data.toMap() to get a Map.
      final Map<String, dynamic> jsonData = data.toMap();
      // --- END: MODIFICATION (FIXED ERROR) ---

      jsonData['submissionStatus'] = data.submissionStatus;
      jsonData['submissionMessage'] = data.submissionMessage;

      jsonData['serverConfigName'] = serverName;

      final imageFiles = data.toApiImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null && imageFile.path.isNotEmpty) {
          try {
            if (p.dirname(imageFile.path) == eventDir.path) {
              jsonData[entry.key] = imageFile.path;
            } else {
              final String originalFileName = p.basename(imageFile.path);
              final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
              jsonData[entry.key] = newFile.path;
            }
          } catch (e) {
            debugPrint("Error processing In-Situ image file ${imageFile.path}: $e");
            jsonData[entry.key] = null;
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("In-Situ log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving In-Situ log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllInSituLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_in_situ_sampling'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading in-situ logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateInSituLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("Log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating in-situ log: $e");
    }
  }

  Future<List<InSituSamplingData>> getRecentNearbySamples({
    required double latitude,
    required double longitude,
    required double radiusKm,
    required int withinHours,
  }) async {
    final allLogs = await getAllInSituLogs();
    final List<InSituSamplingData> recentNearbySamples = [];
    final cutoffDateTime = DateTime.now().subtract(Duration(hours: withinHours));
    final double radiusInMeters = radiusKm * 1000;

    for (var log in allLogs) {
      try {
        final sampleData = InSituSamplingData.fromJson(log);

        if (sampleData.samplingDate == null || sampleData.samplingTime == null) {
          continue;
        }
        final sampleDateTime = DateTime.tryParse('${sampleData.samplingDate} ${sampleData.samplingTime}');
        if (sampleDateTime == null || sampleDateTime.isBefore(cutoffDateTime)) {
          continue;
        }

        final sampleLat = double.tryParse(sampleData.currentLatitude ?? '');
        final sampleLon = double.tryParse(sampleData.currentLongitude ?? '');
        if (sampleLat == null || sampleLon == null) {
          continue;
        }

        final distanceInMeters = Geolocator.distanceBetween(
          latitude,
          longitude,
          sampleLat,
          sampleLon,
        );

        if (distanceInMeters <= radiusInMeters) {
          recentNearbySamples.add(sampleData);
        }
      } catch (e) {
        debugPrint("Error processing in-situ log for nearby search: $e");
      }
    }
    recentNearbySamples.sort((a, b) {
      final dtA = DateTime.tryParse('${a.samplingDate} ${a.samplingTime}');
      final dtB = DateTime.tryParse('${b.samplingDate} ${b.samplingTime}');
      if (dtA == null || dtB == null) return 0;
      return dtB.compareTo(dtA);
    });
    return recentNearbySamples;
  }

  // --- ADDED: Part 4.5: Marine NPE Report Specific Methods ---

  Future<Directory?> _getNpeBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final npeDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_npe_report'));
    if (!await npeDir.exists()) {
      await npeDir.create(recursive: true);
    }
    return npeDir;
  }

  Future<String?> saveNpeReportData(MarineManualNpeReportData data, {required String serverName}) async {
    final baseDir = await _getNpeBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for NPE. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.selectedStation?['man_station_code'] ?? data.selectedStation?['tbl_station_code'] ?? 'CUSTOM_LOC';
      final timestamp = "${data.eventDate}_${data.eventTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_${timestamp}_NPE";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      final Map<String, dynamic> jsonData = data.toDbJson();
      jsonData['serverConfigName'] = serverName;

      final imageFiles = data.toApiImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null && imageFile.path.isNotEmpty) {
          try {
            final String originalFileName = p.basename(imageFile.path);
            final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
            jsonData['image${entry.key.split('_').last}Path'] = newFile.path; // Save as image1Path, etc.
          } catch (e) {
            debugPrint("Error processing NPE image file ${imageFile.path}: $e");
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("NPE Report log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving NPE report to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllNpeLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_npe_report'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading NPE logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateNpeLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) return;

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("NPE Log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating NPE log: $e");
    }
  }

  // =======================================================================
  // --- START: Added Part 4.6: Marine Pre-Departure Methods ---
  // =======================================================================

  Future<Directory?> _getPreDepartureBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final logDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_pre_departure'));
    if (!await logDir.exists()) {
      await logDir.create(recursive: true);
    }
    return logDir;
  }

  Future<String?> savePreDepartureData(MarineManualPreDepartureChecklistData data, {required String serverName}) async {
    final baseDir = await _getPreDepartureBaseDir(serverName: serverName);
    if (baseDir == null) return null;

    try {
      final timestamp = data.submissionDate ?? DateTime.now().toIso8601String();
      final eventFolderName = "checklist_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));
      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      // --- START: MODIFIED BLOCK ---
      // Use toDbJson() for a complete, consistent log
      final Map<String, dynamic> jsonData = data.toDbJson();
      jsonData['serverConfigName'] = serverName;
      // All other fields are now included in toDbJson()
      // --- END: MODIFIED BLOCK ---

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("Pre-Departure log saved to: ${jsonFile.path}");
      return eventDir.path;
    } catch (e) {
      debugPrint("Error saving Pre-Departure log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllPreDepartureLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_pre_departure'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final data = jsonDecode(await jsonFile.readAsString()) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading Pre-Departure logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updatePreDepartureLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) return;
    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
      }
    } catch (e) {
      debugPrint("Error updating Pre-Departure log: $e");
    }
  }

  // =======================================================================
  // --- START: Added Part 4.7: Marine Sonde Calibration Methods ---
  // =======================================================================

  Future<Directory?> _getSondeCalibrationBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final logDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_sonde_calibration'));
    if (!await logDir.exists()) {
      await logDir.create(recursive: true);
    }
    return logDir;
  }

  Future<String?> saveSondeCalibrationData(MarineManualSondeCalibrationData data, {required String serverName}) async {
    final baseDir = await _getSondeCalibrationBaseDir(serverName: serverName);
    if (baseDir == null) return null;

    try {
      final timestamp = data.startDateTime?.replaceAll(':', '-').replaceAll(' ', '_') ?? DateTime.now().toIso8601String();
      final eventFolderName = "calibration_${data.sondeSerialNumber}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));
      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      // --- START: MODIFIED BLOCK ---
      // Use toDbJson() for a complete, consistent log
      final Map<String, dynamic> jsonData = data.toDbJson();
      jsonData['serverConfigName'] = serverName;
      // All other fields are now included in toDbJson()
      // --- END: MODIFIED BLOCK ---

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("Sonde Calibration log saved to: ${jsonFile.path}");
      return eventDir.path;
    } catch (e) {
      debugPrint("Error saving Sonde Calibration log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllSondeCalibrationLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_sonde_calibration'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final data = jsonDecode(await jsonFile.readAsString()) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading Sonde Calibration logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateSondeCalibrationLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) return;
    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
      }
    } catch (e) {
      debugPrint("Error updating Sonde Calibration log: $e");
    }
  }

  // =======================================================================
  // --- START: Added Part 4.8: Marine Equipment Maintenance Methods ---
  // =======================================================================

  Future<Directory?> _getEquipmentMaintenanceBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final logDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_equipment_maintenance'));
    if (!await logDir.exists()) {
      await logDir.create(recursive: true);
    }
    return logDir;
  }

  Future<String?> saveEquipmentMaintenanceData(MarineManualEquipmentMaintenanceData data, {required String serverName}) async {
    final baseDir = await _getEquipmentMaintenanceBaseDir(serverName: serverName);
    if (baseDir == null) return null;

    try {
      final timestamp = data.maintenanceDate ?? DateTime.now().toIso8601String();
      final eventFolderName = "maintenance_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));
      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      // --- START: MODIFIED BLOCK ---
      // Use toDbJson() for a complete, consistent log
      final Map<String, dynamic> jsonData = data.toDbJson();
      jsonData['serverConfigName'] = serverName;
      // All other fields are now included in toDbJson()
      // --- END: MODIFIED BLOCK ---

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("Equipment Maintenance log saved to: ${jsonFile.path}");
      return eventDir.path;
    } catch (e) {
      debugPrint("Error saving Equipment Maintenance log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllEquipmentMaintenanceLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_equipment_maintenance'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final data = jsonDecode(await jsonFile.readAsString()) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading Equipment Maintenance logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateEquipmentMaintenanceLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) return;
    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
      }
    } catch (e) {
      debugPrint("Error updating Equipment Maintenance log: $e");
    }
  }


  // =======================================================================
  // Part 5: River In-Situ Specific Methods (LOGGING RESTORED)
  // =======================================================================

  Future<Directory?> getRiverInSituBaseDir(String? samplingType, {required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    String subfolderName;
    if (samplingType == 'Schedule' || samplingType == 'Triennial') {
      subfolderName = samplingType!;
    } else {
      subfolderName = 'Others';
    }

    final inSituDir = Directory(p.join(mmsv4Dir.path, 'river', 'river_in_situ_sampling', subfolderName));
    if (!await inSituDir.exists()) {
      await inSituDir.create(recursive: true);
    }
    return inSituDir;
  }

  Future<String?> saveRiverInSituSamplingData(RiverInSituSamplingData data, {required String serverName}) async {
    final baseDir = await getRiverInSituBaseDir(data.samplingType, serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for River In-Situ. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.selectedStation?['sampling_station_code'] ?? 'UNKNOWN_STATION';
      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      final Map<String, dynamic> jsonData = data.toMap();
      jsonData['serverConfigName'] = serverName;

      final imageFiles = data.toApiImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null) {
          final String originalFileName = p.basename(imageFile.path);
          if (p.dirname(imageFile.path) == eventDir.path) {
            jsonData[entry.key] = imageFile.path;
          } else {
            final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
            jsonData[entry.key] = newFile.path;
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("River In-Situ log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving River In-Situ log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllRiverInSituLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final topLevelDir = Directory(p.join(serverDir.path, 'river', 'river_in_situ_sampling'));
      if (!await topLevelDir.exists()) continue;
      try {
        final typeSubfolders = topLevelDir.listSync();
        for (var typeSubfolder in typeSubfolders) {
          if (typeSubfolder is Directory) {
            final eventFolders = typeSubfolder.listSync();
            for (var eventFolder in eventFolders) {
              if (eventFolder is Directory) {
                final jsonFile = File(p.join(eventFolder.path, 'data.json'));
                if (await jsonFile.exists()) {
                  final content = await jsonFile.readAsString();
                  final data = jsonDecode(content) as Map<String, dynamic>;
                  data['logDirectory'] = eventFolder.path;
                  allLogs.add(data);
                }
              }
            }
          }
        }
      } catch (e) {
        debugPrint("Error getting all river in-situ logs from ${topLevelDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateRiverInSituLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("Log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating river in-situ log: $e");
    }
  }

  // =======================================================================
  // Part 6: River Triennial Specific Methods
  // =======================================================================

  Future<Directory?> _getRiverTriennialBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final triennialDir = Directory(p.join(mmsv4Dir.path, 'river', 'river_triennial_sampling'));
    if (!await triennialDir.exists()) {
      await triennialDir.create(recursive: true);
    }
    return triennialDir;
  }

  Future<String?> saveRiverManualTriennialSamplingData(RiverManualTriennialSamplingData data, {required String serverName}) async {
    final baseDir = await _getRiverTriennialBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for River Triennial. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.selectedStation?['sampling_station_code'] ?? 'UNKNOWN_STATION';
      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      final Map<String, dynamic> jsonData = data.toMap();
      jsonData['serverConfigName'] = serverName;

      final imageFiles = data.toApiImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null) {
          final String originalFileName = p.basename(imageFile.path);
          if (p.dirname(imageFile.path) == eventDir.path) {
            jsonData[entry.key] = imageFile.path;
          } else {
            final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
            jsonData[entry.key] = newFile.path;
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("River Triennial log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving River Triennial log to local storage: $e");
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> getAllRiverManualTriennialLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'river', 'river_triennial_sampling'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading triennial logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  Future<void> updateRiverManualTriennialLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting');
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("Log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating river triennial log: $e");
    }
  }

  // =======================================================================
  // --- ADDED: Part 6.5: Marine Investigative Specific Methods ---
  // =======================================================================

  Future<Directory?> _getInvestigativeBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    // Use a new subModule path for investigative logs
    final inSituDir = Directory(p.join(mmsv4Dir.path, 'marine', 'marine_investigative_sampling'));
    if (!await inSituDir.exists()) {
      await inSituDir.create(recursive: true);
    }
    return inSituDir;
  }

  /// Saves Marine Investigative sampling data to the local log
  Future<String?> saveInvestigativeSamplingData(MarineInvesManualSamplingData data, {required String serverName}) async {
    final baseDir = await _getInvestigativeBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for Investigative. Check permissions.");
      return null;
    }

    try {
      // --- Generate folder name based on station type ---
      String stationCode = 'NA';
      if (data.stationTypeSelection == 'Existing Manual Station') {
        stationCode = data.selectedStation?['man_station_code'] ?? 'MANUAL_NA';
      } else if (data.stationTypeSelection == 'Existing Tarball Station') {
        stationCode = data.selectedTarballStation?['tbl_station_code'] ?? 'TARBALL_NA';
      } else if (data.stationTypeSelection == 'New Location') {
        stationCode = data.newStationCode ?? 'NEW_NA';
      }

      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      final Map<String, dynamic> jsonData = data.toDbJson(); //
      jsonData['submissionStatus'] = data.submissionStatus;
      jsonData['submissionMessage'] = data.submissionMessage;
      jsonData['reportId'] = data.reportId;
      jsonData['serverConfigName'] = serverName;

      final imageFiles = data.toApiImageFiles(); //
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null && imageFile.path.isNotEmpty) {
          try {
            // Check if file is already in the correct directory (e.g., from a retry)
            if (p.dirname(imageFile.path) == eventDir.path) {
              jsonData[entry.key] = imageFile.path;
            } else {
              // Copy file from temp cache to persistent log directory
              final String originalFileName = p.basename(imageFile.path);
              final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
              jsonData[entry.key] = newFile.path;
            }
          } catch (e) {
            debugPrint("Error processing Investigative image file ${imageFile.path}: $e");
            jsonData[entry.key] = null;
          }
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("Investigative log saved to: ${jsonFile.path}");

      return eventDir.path; // Return the path to the saved log directory

    } catch (e) {
      debugPrint("Error saving Investigative log to local storage: $e");
      return null;
    }
  }

  /// Fetches all saved Marine Investigative logs
  Future<List<Map<String, dynamic>>> getAllInvestigativeLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'marine', 'marine_investigative_sampling'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading investigative logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  /// Updates an existing Marine Investigative log file (e.g., after a retry)
  Future<void> updateInvestigativeLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update investigative log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting'); // Clean up temporary flags
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("Investigative log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating investigative log: $e");
    }
  }

  // =======================================================================
  // --- ADDED: Part 6.6: River Investigative Specific Methods ---
  // =======================================================================

  /// Gets the base directory for River Investigative logs.
  Future<Directory?> getRiverInvestigativeBaseDir({required String serverName}) async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: serverName);
    if (mmsv4Dir == null) return null;

    final invesDir = Directory(p.join(mmsv4Dir.path, 'river', 'river_investigative_sampling'));
    if (!await invesDir.exists()) {
      await invesDir.create(recursive: true);
    }
    return invesDir;
  }

  /// Saves River Investigative sampling data to the local log.
  Future<String?> saveRiverInvestigativeSamplingData(RiverInvesManualSamplingData data, {required String serverName}) async {
    final baseDir = await getRiverInvestigativeBaseDir(serverName: serverName);
    if (baseDir == null) {
      debugPrint("Could not get public storage directory for River Investigative. Check permissions.");
      return null;
    }

    try {
      final stationCode = data.getDeterminedStationCode() ?? 'UNKNOWN';
      final timestamp = "${data.samplingDate}_${data.samplingTime?.replaceAll(':', '-')}";
      final eventFolderName = "${stationCode}_$timestamp";
      final eventDir = Directory(p.join(baseDir.path, eventFolderName));

      if (!await eventDir.exists()) {
        await eventDir.create(recursive: true);
      }

      // Use the .toMap() method from the data model, which is designed for local logging
      final Map<String, dynamic> jsonData = data.toMap();
      jsonData['serverConfigName'] = serverName;
      // Status, message, and reportId are already included by .toMap()

      final imageFiles = data.toApiImageFiles();
      for (var entry in imageFiles.entries) {
        final File? imageFile = entry.value;
        if (imageFile != null && imageFile.path.isNotEmpty) {
          try {
            if (p.dirname(imageFile.path) == eventDir.path) {
              jsonData[entry.key] = imageFile.path; // Already in log dir
            } else {
              final String originalFileName = p.basename(imageFile.path);
              final File newFile = await imageFile.copy(p.join(eventDir.path, originalFileName));
              jsonData[entry.key] = newFile.path; // Store the new persistent path
            }
          } catch (e) {
            debugPrint("Error processing River Investigative image file ${imageFile.path}: $e");
            jsonData[entry.key] = null; // Store null if copy failed
          }
        } else {
          // Ensure keys for null images are also present if needed, though .toMap() handles this
          jsonData[entry.key] = null;
        }
      }

      final jsonFile = File(p.join(eventDir.path, 'data.json'));
      await jsonFile.writeAsString(jsonEncode(jsonData));
      debugPrint("River Investigative log saved to: ${jsonFile.path}");

      return eventDir.path;

    } catch (e) {
      debugPrint("Error saving River Investigative log to local storage: $e");
      return null;
    }
  }

  /// Fetches all saved River Investigative logs.
  Future<List<Map<String, dynamic>>> getAllRiverInvestigativeLogs() async {
    final mmsv4Root = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Root == null || !await mmsv4Root.exists()) return [];

    final List<Map<String, dynamic>> allLogs = [];
    final serverDirs = mmsv4Root.listSync().whereType<Directory>();

    for (var serverDir in serverDirs) {
      final baseDir = Directory(p.join(serverDir.path, 'river', 'river_investigative_sampling'));
      if (!await baseDir.exists()) continue;
      try {
        final entities = baseDir.listSync();
        for (var entity in entities) {
          if (entity is Directory) {
            final jsonFile = File(p.join(entity.path, 'data.json'));
            if (await jsonFile.exists()) {
              final content = await jsonFile.readAsString();
              final data = jsonDecode(content) as Map<String, dynamic>;
              data['logDirectory'] = entity.path;
              allLogs.add(data);
            }
          }
        }
      } catch (e) {
        debugPrint("Error reading river investigative logs from ${baseDir.path}: $e");
      }
    }
    return allLogs;
  }

  /// Updates an existing River Investigative log file (e.g., after a retry).
  Future<void> updateRiverInvestigativeLog(Map<String, dynamic> updatedLogData) async {
    final logDir = updatedLogData['logDirectory'];
    if (logDir == null) {
      debugPrint("Cannot update river investigative log: logDirectory key is missing.");
      return;
    }

    try {
      final jsonFile = File(p.join(logDir, 'data.json'));
      if (await jsonFile.exists()) {
        updatedLogData.remove('isResubmitting'); // Clean up temporary flags
        await jsonFile.writeAsString(jsonEncode(updatedLogData));
        debugPrint("River Investigative log updated successfully at: ${jsonFile.path}");
      }
    } catch (e) {
      debugPrint("Error updating river investigative log: $e");
    }
  }


  // =======================================================================
  // --- ADDED: Part 7: Info Centre Document Management ---
  // =======================================================================

  final Dio _dio = Dio();

  Future<Directory?> _getInfoCentreDocumentsDirectory() async {
    final mmsv4Dir = await _getPublicMMSV4Directory(serverName: '');
    if (mmsv4Dir == null) return null;

    final docDir = Directory(p.join(mmsv4Dir.path, 'info_centre_documents'));
    if (!await docDir.exists()) {
      await docDir.create(recursive: true);
    }
    return docDir;
  }

  Future<String?> getLocalDocumentPath(String docUrl) async {
    final docDir = await _getInfoCentreDocumentsDirectory();
    if (docDir == null) return null;

    final fileName = p.basename(docUrl);
    return p.join(docDir.path, fileName);
  }

  Future<bool> isDocumentDownloaded(String docUrl) async {
    final filePath = await getLocalDocumentPath(docUrl);
    if (filePath == null) return false;
    return await File(filePath).exists();
  }

  Future<void> downloadDocument({
    required String docUrl,
    required Function(double) onReceiveProgress,
  }) async {
    final filePath = await getLocalDocumentPath(docUrl);
    if (filePath == null) {
      throw Exception("Could not get local storage path. Check permissions.");
    }

    try {
      await _dio.download(
        docUrl,
        filePath,
        onReceiveProgress: (received, total) {
          if (total != -1) {
            onReceiveProgress(received / total);
          }
        },
      );
    } catch (e) {
      final file = File(filePath);
      if (await file.exists()) {
        await file.delete();
      }
      throw Exception("Download failed: $e");
    }
  }
}