// lib/services/river_in_situ_sampling_service.dart

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:image/image.dart' as img;
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:usb_serial/usb_serial.dart';

// CHANGED: Import river-specific services and models
import 'location_service.dart';
import 'river_api_service.dart';
import '../models/river_in_situ_sampling_data.dart';
import '../bluetooth/bluetooth_manager.dart';
import '../serial/serial_manager.dart';

/// A dedicated service to handle all business logic for the River In-Situ Sampling feature.
// CHANGED: Renamed class for the River In-Situ Sampling Service
class RiverInSituSamplingService {
  final LocationService _locationService = LocationService();
  // CHANGED: Use the river-specific API service
  final RiverApiService _riverApiService = RiverApiService();
  final BluetoothManager _bluetoothManager = BluetoothManager();
  final SerialManager _serialManager = SerialManager();

  // This channel name MUST match the one defined in MainActivity.kt
  static const platform = MethodChannel('com.example.environment_monitoring_app/usb');


  // --- Location Services ---
  Future<Position> getCurrentLocation() => _locationService.getCurrentLocation();
  double calculateDistance(double lat1, double lon1, double lat2, double lon2) => _locationService.calculateDistance(lat1, lon1, lat2, lon2);

  // --- Image Processing ---
  Future<File?> pickAndProcessImage(ImageSource source, {
    // CHANGED: Use the river-specific data model
    required RiverInSituSamplingData data,
    required String imageInfo,
    bool isRequired = false,
    String? stationCode, // Accept station code for naming
  }) async {
    final picker = ImagePicker();
    final XFile? photo = await picker.pickImage(source: source, imageQuality: 85, maxWidth: 1024);
    if (photo == null) return null;

    final bytes = await photo.readAsBytes();
    img.Image? originalImage = img.decodeImage(bytes);
    if (originalImage == null) return null;

    if (isRequired && originalImage.height > originalImage.width) {
      debugPrint("Image rejected: Must be in landscape orientation.");
      return null;
    }

    final String watermarkTimestamp = "${data.samplingDate} ${data.samplingTime}";
    final font = img.arial24;
    final textWidth = watermarkTimestamp.length * 12;
    img.fillRect(originalImage, x1: 5, y1: 5, x2: textWidth + 15, y2: 35, color: img.ColorRgb8(255, 255, 255));
    img.drawString(originalImage, watermarkTimestamp, font: font, x: 10, y: 10, color: img.ColorRgb8(0, 0, 0));

    final tempDir = await getTemporaryDirectory();
    final finalStationCode = stationCode ?? 'NA';
    final fileTimestamp = "${data.samplingDate}-${data.samplingTime}".replaceAll(':', '-');
    final newFileName = "${finalStationCode}_${fileTimestamp}_${imageInfo.replaceAll(' ', '')}.jpg";
    final filePath = path.join(tempDir.path, newFileName);

    return File(filePath)..writeAsBytesSync(img.encodeJpg(originalImage));
  }

  // --- Device Connection (Delegated to Managers) ---
  ValueNotifier<BluetoothConnectionState> get bluetoothConnectionState => _bluetoothManager.connectionState;
  ValueNotifier<SerialConnectionState> get serialConnectionState => _serialManager.connectionState;

  // This getter now dynamically returns the correct Sonde ID notifier
  // based on the active connection, which is essential for the UI.
  ValueNotifier<String?> get sondeId {
    if (_bluetoothManager.connectionState.value != BluetoothConnectionState.disconnected) {
      return _bluetoothManager.sondeId;
    }
    return _serialManager.sondeId;
  }

  Stream<Map<String, double>> get bluetoothDataStream => _bluetoothManager.dataStream;
  Stream<Map<String, double>> get serialDataStream => _serialManager.dataStream;

  String? get connectedBluetoothDeviceName => _bluetoothManager.connectedDeviceName.value;
  String? get connectedSerialDeviceName => _serialManager.connectedDeviceName.value;

  // --- Permissions ---
  Future<bool> requestDevicePermissions() async {
    Map<Permission, PermissionStatus> statuses = await [
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
      Permission.locationWhenInUse,
    ].request();

    // Return true only if the essential permissions are granted.
    if (statuses[Permission.bluetoothScan] == PermissionStatus.granted &&
        statuses[Permission.bluetoothConnect] == PermissionStatus.granted) {
      return true;
    } else {
      return false;
    }
  }

  // --- Bluetooth Methods ---
  Future<List<BluetoothDevice>> getPairedBluetoothDevices() => _bluetoothManager.getPairedDevices();
  Future<void> connectToBluetoothDevice(BluetoothDevice device) => _bluetoothManager.connect(device);
  void disconnectFromBluetooth() => _bluetoothManager.disconnect();
  void startBluetoothAutoReading({Duration? interval}) => _bluetoothManager.startAutoReading(interval: interval ?? const Duration(seconds: 5));
  void stopBluetoothAutoReading() => _bluetoothManager.stopAutoReading();


  // --- USB Serial Methods ---
  Future<List<UsbDevice>> getAvailableSerialDevices() => _serialManager.getAvailableDevices();

  Future<bool> requestUsbPermission(UsbDevice device) async {
    try {
      return await platform.invokeMethod('requestUsbPermission', {'vid': device.vid, 'pid': device.pid}) ?? false;
    } on PlatformException catch (e) {
      debugPrint("Failed to request USB permission: '${e.message}'.");
      return false;
    }
  }

  Future<void> connectToSerialDevice(UsbDevice device) async {
    final bool permissionGranted = await requestUsbPermission(device);
    if (permissionGranted) {
      await _serialManager.connect(device);
    } else {
      throw Exception("USB permission was not granted.");
    }
  }

  void disconnectFromSerial() => _serialManager.disconnect();
  void startSerialAutoReading({Duration? interval}) => _serialManager.startAutoReading(interval: interval ?? const Duration(seconds: 5));
  void stopSerialAutoReading() => _serialManager.stopAutoReading();


  void dispose() {
    _bluetoothManager.dispose();
    _serialManager.dispose();
  }

  // --- Data Submission ---
  // CHANGED: Use the river-specific data model
  Future<Map<String, dynamic>> submitData(RiverInSituSamplingData data) {
    // CHANGED: Call the river-specific API service method
    return _riverApiService.submitInSituSample(
      formData: data.toApiFormData(),
      imageFiles: data.toApiImageFiles(),
    );
  }
}
