// lib/services/marine_manual_sonde_calibration_service.dart

import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:path/path.dart' as p;

import '../auth_provider.dart';
import '../models/marine_manual_sonde_calibration_data.dart';
import 'api_service.dart';
import 'package:environment_monitoring_app/services/database_helper.dart';
import 'package:environment_monitoring_app/services/local_storage_service.dart';
import 'package:environment_monitoring_app/services/server_config_service.dart';
import 'package:environment_monitoring_app/services/retry_service.dart';
import 'package:environment_monitoring_app/services/submission_api_service.dart';
import 'package:environment_monitoring_app/services/submission_ftp_service.dart';
import 'package:environment_monitoring_app/services/zipping_service.dart';
import 'user_preferences_service.dart'; // ADDED
import 'telegram_service.dart'; // --- ADDED IMPORT ---

import 'base_api_service.dart'; // Import for SessionExpiredException

class MarineManualSondeCalibrationService {
  final SubmissionApiService _submissionApiService = SubmissionApiService();
  final SubmissionFtpService _submissionFtpService = SubmissionFtpService();
  final ZippingService _zippingService = ZippingService();
  final LocalStorageService _localStorageService = LocalStorageService();
  final ServerConfigService _serverConfigService = ServerConfigService();
  final UserPreferencesService _userPreferencesService = UserPreferencesService(); // ADDED
  final DatabaseHelper _dbHelper = DatabaseHelper();
  final RetryService _retryService = RetryService();
  final TelegramService _telegramService; // --- ADDED FIELD ---

  // The ApiService is kept only if other non-submission methods need it.
  // --- MODIFIED CONSTRUCTOR ---
  MarineManualSondeCalibrationService(ApiService apiService, this._telegramService);

  /// Fetches all Calibration logs stored locally on the device.
  Future<List<Map<String, dynamic>>> getLocalCalibrationLogs() async {
    return await _localStorageService.getAllSondeCalibrationLogs();
  }

  /// Main submission method with online/offline branching logic
  Future<Map<String, dynamic>> submitCalibration({
    required MarineManualSondeCalibrationData data,
    required AuthProvider authProvider,
    List<Map<String, dynamic>>? appSettings,
    BuildContext? context,
    String? logDirectory,
  }) async {
    // Unified module name for preferences
    const String moduleName = 'marine_report';

    // Populate the user name from the AuthProvider
    data.calibratedByUserName = authProvider.profileData?['first_name'] as String?;

    final connectivityResult = await Connectivity().checkConnectivity();
    bool isOnline = !connectivityResult.contains(ConnectivityResult.none);
    bool isOfflineSession = authProvider.isLoggedIn &&
        (authProvider.profileData?['token']?.startsWith("offline-session-") ?? false);

    if (isOnline && isOfflineSession) {
      debugPrint(
          "$moduleName submission online during offline session. Attempting auto-relogin...");
      final bool transitionSuccess =
      await authProvider.checkAndTransitionToOnlineSession();
      if (transitionSuccess) {
        isOfflineSession = false;
      } else {
        isOnline = false;
      }
    }

    if (isOnline && !isOfflineSession) {
      debugPrint("Proceeding with direct ONLINE $moduleName submission...");
      return await _performOnlineSubmission(
        data: data,
        moduleName: moduleName,
        authProvider: authProvider,
        logDirectory: logDirectory,
      );
    } else {
      debugPrint("Proceeding with OFFLINE $moduleName queuing mechanism...");
      return await _performOfflineQueuing(
        data: data,
        moduleName: moduleName,
      );
    }
  }

  /// Handles the direct online submission.
  Future<Map<String, dynamic>> _performOnlineSubmission({
    required MarineManualSondeCalibrationData data,
    required String moduleName,
    required AuthProvider authProvider,
    String? logDirectory,
  }) async {
    final serverName =
        (await _serverConfigService.getActiveApiConfig())?['config_name']
        as String? ??
            'Default';
    bool anyApiSuccess = false;
    Map<String, dynamic> apiResult = {};

    // 1. API Submission
    // Check if API is enabled in preferences
    final pref = await _userPreferencesService.getModulePreference(moduleName);
    bool isApiEnabled = pref?['is_api_enabled'] ?? true;

    if (isApiEnabled) {
      try {
        apiResult = await _submissionApiService.submitPost(
          moduleName: moduleName,
          endpoint: 'marine/calibration', // Endpoint from marine_api_service.dart
          body: data.toApiFormData(),
        );

        if (apiResult['success'] == false && (apiResult['message'] as String?)?.contains('Unauthorized') == true) {
          // Handle silent relogin
          if (await authProvider.attemptSilentRelogin()) {
            apiResult = await _submissionApiService.submitPost(
              moduleName: moduleName,
              endpoint: 'marine/calibration',
              body: data.toApiFormData(),
            );
          }
        }

        if (apiResult['success'] == true) {
          anyApiSuccess = true;
          data.reportId = apiResult['data']?['calibration_id']?.toString();
        }
      } on SocketException catch (e) {
        apiResult = {
          'success': false,
          'message': "API submission failed with network error: $e"
        };
        // Queue API manually
        await _retryService.addApiToQueue(endpoint: 'marine/calibration', method: 'POST', body: data.toApiFormData());
      } on TimeoutException catch (e) {
        apiResult = {
          'success': false,
          'message': "API submission timed out: $e"
        };
        await _retryService.addApiToQueue(endpoint: 'marine/calibration', method: 'POST', body: data.toApiFormData());
      } catch (e) {
        apiResult = {
          'success': false,
          'message': 'An unexpected error occurred: $e'
        };
      }
    } else {
      anyApiSuccess = true; // Treated as success if disabled by user
    }

    // 2. FTP Submission (Data Zip Only - No Images for Calibration)
    Map<String, dynamic> ftpResults = {'statuses': []};
    bool anyFtpSuccess = false;

    bool isFtpEnabled = pref?['is_ftp_enabled'] ?? true;
    // Check status to avoid duplicate uploads (L4 = API Fail, FTP Success; S4 = Both Success)
    bool previousFtpSuccess = data.submissionStatus == 'L4' || data.submissionStatus == 'S4';
    // Check active FTPs
    final enabledFtpConfigs = await _userPreferencesService.getEnabledFtpConfigsForModule(moduleName);

    if (!isFtpEnabled) {
      ftpResults = {'statuses': [{'status': 'Skipped', 'message': 'FTP disabled by user.', 'success': true}]};
      anyFtpSuccess = true;
    } else if (previousFtpSuccess) {
      debugPrint("FTP submission skipped: Already successful in previous attempt.");
      ftpResults = {'statuses': [{'status': 'Skipped', 'message': 'Already successful.', 'success': true}]};
      anyFtpSuccess = true;
    } else if (enabledFtpConfigs.isEmpty) {
      debugPrint("FTP submission skipped: No active FTP configurations found for $moduleName.");
      ftpResults = {'statuses': [{'status': 'Skipped', 'message': 'No active FTP servers.', 'success': true}]};
      anyFtpSuccess = true;
    } else {
      try {
        ftpResults = await _generateAndUploadFtpFiles(data, serverName, moduleName);
        anyFtpSuccess = !(ftpResults['statuses'] as List).any((status) => status['success'] == false && status['status'] != 'Not Configured');
      } catch (e) {
        debugPrint("FTP submission error: $e");
        anyFtpSuccess = false;
      }
    }

    // 3. Determine Final Status
    final bool overallSuccess = anyApiSuccess || anyFtpSuccess;
    String finalMessage;
    String finalStatus;

    if (anyApiSuccess && anyFtpSuccess) {
      finalMessage = 'Calibration submitted successfully to all destinations.';
      finalStatus = 'S4';
    } else if (anyApiSuccess && !anyFtpSuccess) {
      finalMessage = 'Calibration sent to API, but FTP upload failed.';
      finalStatus = 'S3';
    } else if (!anyApiSuccess && anyFtpSuccess) {
      finalMessage = 'API submission failed, but file sent to FTP.';
      finalStatus = 'L4';
    } else {
      finalMessage = apiResult['message'] ?? 'All submission attempts failed.';
      finalStatus = 'L1';
    }

    await _logAndSave(
      data: data,
      status: finalStatus,
      message: finalMessage,
      apiResult: apiResult,
      ftpStatuses: ftpResults['statuses'],
      serverName: serverName,
      logDirectory: logDirectory,
    );

    // --- START: ADDED TELEGRAM ALERT ---
    if (overallSuccess) {
      _handleSuccessAlert(data, authProvider);
    }
    // --- END: ADDED TELEGRAM ALERT ---

    return {'success': overallSuccess, 'message': finalMessage};
  }

  /// Handles saving the submission to local storage and queuing for retry.
  Future<Map<String, dynamic>> _performOfflineQueuing({
    required MarineManualSondeCalibrationData data,
    required String moduleName,
  }) async {
    final serverConfig = await _serverConfigService.getActiveApiConfig();
    final serverName =
        serverConfig?['config_name'] as String? ?? 'Default';

    data.submissionStatus = 'L1';
    data.submissionMessage = 'Sonde Calibration queued due to being offline.';

    // This method is added to LocalStorageService
    final String? localLogPath =
    await _localStorageService.saveSondeCalibrationData(data, serverName: serverName);

    if (localLogPath == null) {
      const message =
          "Failed to save Sonde Calibration to local device storage.";
      await _logAndSave(
          data: data,
          status: 'Error',
          message: message,
          apiResult: {},
          ftpStatuses: [],
          serverName: serverName);
      return {'success': false, 'message': message};
    }

    await _retryService.queueTask(
      type: 'sonde_calibration_submission', // New task type
      payload: {
        'module': moduleName,
        'localLogPath': localLogPath,
        'serverConfig': serverConfig,
      },
    );

    const successMessage =
        "No internet connection. Sonde Calibration has been saved and queued for upload.";
    return {'success': true, 'message': successMessage};
  }

  /// Generates zip files and uploads them via FTP.
  Future<Map<String, dynamic>> _generateAndUploadFtpFiles(MarineManualSondeCalibrationData data, String serverName, String moduleName) async {
    final fileTimestamp = data.startDateTime?.replaceAll(':', '-').replaceAll(' ', '_') ?? DateTime.now().toIso8601String();
    final baseFileName = 'calibration_${data.sondeSerialNumber}_$fileTimestamp';

    final Directory? logDirectory = await _localStorageService.getLogDirectory(
      serverName: serverName,
      module: 'marine',
      subModule: 'marine_sonde_calibration',
    );

    final Directory? localSubmissionDir = logDirectory != null ? Directory(p.join(logDirectory.path, baseFileName)) : null;
    if (localSubmissionDir != null && !await localSubmissionDir.exists()) {
      await localSubmissionDir.create(recursive: true);
    }

    final dataZip = await _zippingService.createDataZip(
      jsonDataMap: {'db.json': jsonEncode(data.toDbJson())},
      baseFileName: baseFileName,
      destinationDir: localSubmissionDir,
    );

    Map<String, dynamic> ftpDataResult = {'success': true, 'statuses': []};
    if (dataZip != null) {
      ftpDataResult = await _submissionFtpService.submit(
          moduleName: moduleName,
          fileToUpload: dataZip, // Added ! to ensure non-nullable
          remotePath: '/${p.basename(dataZip.path)}'
      );
    }

    return {'statuses': ftpDataResult['statuses'] ?? []};
  }

  /// Logs the submission to the local file system and the central SQL database.
  Future<void> _logAndSave({
    required MarineManualSondeCalibrationData data,
    required String status,
    required String message,
    required Map<String, dynamic> apiResult,
    required List<Map<String, dynamic>> ftpStatuses,
    required String serverName,
    String? logDirectory,
  }) async {
    data.submissionStatus = status;
    data.submissionMessage = message;

    final fileTimestamp = data.startDateTime?.replaceAll(':', '-').replaceAll(' ', '_') ?? DateTime.now().toIso8601String();

    // Use the new toDbJson() method to get ALL data for logging
    final Map<String, dynamic> logDataMap = data.toDbJson();
    // Add submission-specific metadata
    logDataMap['api_status'] = jsonEncode(apiResult);
    logDataMap['ftp_status'] = jsonEncode(ftpStatuses);
    logDataMap['serverConfigName'] = serverName;

    if (logDirectory != null) {
      // This is an update to an existing log file
      logDataMap['logDirectory'] = logDirectory; // Ensure logDirectory is in the map
      await _localStorageService.updateSondeCalibrationLog(logDataMap);
    } else {
      // This is a new log
      await _localStorageService.saveSondeCalibrationData(data, serverName: serverName);
    }

    final logData = {
      'submission_id': data.reportId ?? fileTimestamp,
      'module': 'marine',
      'type': 'Sonde Calibration',
      'status': data.submissionStatus,
      'message': data.submissionMessage,
      'report_id': data.reportId,
      'created_at': DateTime.now().toIso8601String(),
      // --- START: MODIFIED LINE ---
      'form_data': jsonEncode(data.toDbJson()), // Log the full DbJson
      // --- END: MODIFIED LINE ---
      'image_data': null, // No images
      'server_name': serverName,
      'api_status': jsonEncode(apiResult),
      'ftp_status': jsonEncode(ftpStatuses),
    };
    await _dbHelper.saveSubmissionLog(logData);
  }

  // --- START: NEW TELEGRAM ALERT METHOD ---
  Future<void> _handleSuccessAlert(MarineManualSondeCalibrationData data, AuthProvider authProvider) async {
    try {
      final message = data.generateTelegramAlertMessage();
      // Using 'marine_npe_report' ID/module config as requested
      if (!await _telegramService.sendAlertImmediately('marine_npe_report', message, authProvider.appSettings)) {
        await _telegramService.queueMessage('marine_npe_report', message, authProvider.appSettings);
      }
    } catch (e) {
      debugPrint("Telegram Alert Error (Calibration): $e");
    }
  }
// --- END: NEW TELEGRAM ALERT METHOD ---
}