import 'dart:async';
import 'dart:math';

import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
import 'package:battery_plus/battery_plus.dart'; // **إضافة جديدة:** للتعامل مع حالة البطارية

import 'package:sefer_driver/constant/table_names.dart';
import '../../constant/box_name.dart';
import '../../constant/links.dart';
import '../../main.dart';
import '../../print.dart';
import '../home/captin/home_captain_controller.dart';
import '../home/payment/captain_wallet_controller.dart';
import 'crud.dart';

/// LocationController - النسخة النهائية المتكاملة مع وضع توفير الطاقة
///
/// تم تصميم هذا المتحكم ليكون المحرك الجديد لإدارة الموقع في تطبيقك.
/// يجمع بين الكفاءة العالية، المنطق الذكي، والتوافق الكامل مع بنية الكود الحالية.
class LocationController extends GetxController {
  // ===================================================================
  // ====== Tunables / المتغيرات القابلة للتعديل ======
  // ===================================================================
  // -- Normal Mode --
  static const double onMoveMetersNormal = 15.0;
  static const double offMoveMetersNormal = 200.0;
  static const Duration trackInsertEveryNormal = Duration(minutes: 1);
  static const Duration heartbeatEveryNormal = Duration(minutes: 2);

  // -- Power Saving Mode --
  static const double onMoveMetersPowerSave = 75.0;
  static const double offMoveMetersPowerSave = 500.0;
  static const Duration trackInsertEveryPowerSave = Duration(minutes: 2);
  static const Duration heartbeatEveryPowerSave = Duration(minutes: 5);

  static const double lowWalletThreshold = -30000;
  static const int powerSaveTriggerLevel =
      20; // نسبة البطارية لتفعيل وضع التوفير
  static const int powerSaveExitLevel =
      25; // نسبة البطارية للخروج من وضع التوفير

  // ===================================================================
  // ====== Services & Subscriptions (الخدمات والاشتراكات) ======
  // ===================================================================
  late final Location location = Location();
  final Battery _battery = Battery(); // **إضافة جديدة:** للتعامل مع البطارية
  StreamSubscription<LocationData>? _locSub;
  StreamSubscription<BatteryState>? _batterySub;
  Timer? _trackInsertTimer;
  Timer? _heartbeatTimer;

  // ===================================================================
  // ====== Cached Controllers (لتجنب Get.find المتكرر) ======
  // ===================================================================
  late final HomeCaptainController _homeCtrl;
  late final CaptainWalletController _walletCtrl;

  // ===================================================================
  // ====== Public state (لواجهة المستخدم والكلاسات الأخرى) ======
  // ===================================================================
  LatLng myLocation = const LatLng(0, 0);
  double heading = 0.0;
  double speed = 0.0;
  double totalDistance = 0.0;

  // ===================================================================
  // ====== Internal state (للمنطق الداخلي) ======
  // ===================================================================
  bool _isReady = false;
  bool _isPowerSavingMode = false; // **إضافة جديدة:** لتتبع وضع توفير الطاقة
  LatLng? _lastSentLoc;
  String? _lastSentStatus;
  DateTime? _lastSentAt;
  LatLng? _lastPosForDistance;

  // **إضافة جديدة:** متغيرات لحساب سلوك السائق
  LatLng? _lastSqlLoc;
  double? _lastSpeed;
  DateTime? _lastSpeedAt;

  @override
  Future<void> onInit() async {
    super.onInit();
    print('LocationController onInit started...');

    bool dependenciesReady = await _awaitDependencies();
    if (!dependenciesReady) {
      print(
          "❌ CRITICAL ERROR: Dependencies not found. Location services will not start.");
      return;
    }

    _isReady = true;

    await _initLocationSettings();
    await startLocationUpdates();
    _listenToBatteryChanges(); // **إضافة جديدة:** بدء الاستماع لتغيرات البطارية

    print('✅ LocationController is ready and initialized.');
  }

  @override
  void onClose() {
    print('🛑 Closing LocationController...');
    stopLocationUpdates();
    _batterySub?.cancel(); // إيقاف الاستماع للبطارية
    super.onClose();
  }

  Future<bool> _awaitDependencies() async {
    // ... (الكود لم يتغير)
    int attempts = 0;
    while (attempts < 10) {
      if (Get.isRegistered<HomeCaptainController>() &&
          Get.isRegistered<CaptainWalletController>()) {
        _homeCtrl = Get.find<HomeCaptainController>();
        _walletCtrl = Get.find<CaptainWalletController>();
        print("✅ Dependencies found and controllers are cached.");
        return true;
      }
      await Future.delayed(const Duration(milliseconds: 500));
      attempts++;
    }
    return false;
  }

  // ===================================================================
  // ====== Public Control Methods (دوال التحكم العامة) ======
  // ===================================================================

  Future<void> startLocationUpdates() async {
    // ... (الكود لم يتغير)
    if (!_isReady) {
      print("Cannot start updates: LocationController is not ready.");
      return;
    }
    final points = _walletCtrl.totalPoints;
    if (double.parse(points) <= lowWalletThreshold) {
      print('❌ Blocked: low wallet balance ($points)');
      stopLocationUpdates();
      return;
    }
    if (_locSub != null) {
      print('Location updates are already active.');
      return;
    }
    if (await _ensureServiceAndPermission()) {
      _subscribeLocationStream();
      _startTimers();
    }
  }

  void stopLocationUpdates() {
    // ... (الكود لم يتغير)
    _locSub?.cancel();
    _locSub = null;
    _trackInsertTimer?.cancel();
    _trackInsertTimer = null;
    _heartbeatTimer?.cancel();
    _heartbeatTimer = null;
    print('Location updates and timers stopped.');
  }

  Future<LocationData?> getLocation() async {
    // ... (الكود لم يتغير)
    try {
      if (await _ensureServiceAndPermission()) {
        return await location.getLocation();
      }
    } catch (e) {
      print('❌ FAILED to get single location: $e');
    }
    return null;
  }

  // ===================================================================
  // ====== Core Logic (المنطق الأساسي) ======
  // ===================================================================

  Future<void> _initLocationSettings() async {
    // ... (الكود لم يتغير)
    await location.changeSettings(
      accuracy: LocationAccuracy.high,
      interval: 5000,
      distanceFilter: 0,
    );
    await location.enableBackgroundMode(enable: true);
  }

  Future<bool> _ensureServiceAndPermission() async {
    // ... (الكود لم يتغير)
    bool serviceEnabled = await location.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await location.requestService();
      if (!serviceEnabled) return false;
    }
    var perm = await location.hasPermission();
    if (perm == PermissionStatus.denied) {
      perm = await location.requestPermission();
      if (perm != PermissionStatus.granted) return false;
    }
    return true;
  }

  void _subscribeLocationStream() {
    _locSub?.cancel();
    _locSub = location.onLocationChanged.listen(
      (loc) async {
        if (!_isReady) return;
        try {
          if (loc.latitude == null || loc.longitude == null) return;
          final now = DateTime.now();
          final pos = LatLng(loc.latitude!, loc.longitude!);

          myLocation = pos;
          speed = loc.speed ?? 0.0;
          heading = loc.heading ?? 0.0;

          if (_lastPosForDistance != null) {
            final d = _haversineMeters(_lastPosForDistance!, pos);
            if (d > 2.0) totalDistance += d;
          }
          _lastPosForDistance = pos;
          // ✅ تحديث الكاميرا
          // _homeCtrl.mapHomeCaptainController?.animateCamera(
          //   CameraUpdate.newCameraPosition(
          //     CameraPosition(
          //       bearing: Get.find<LocationController>().heading,
          //       target: myLocation,
          //       zoom: 17, // Adjust zoom level as needed
          //     ),
          //   ),
          // );
          update(); // تحديث الواجهة الرسومية بالبيانات الجديدة

          await _smartSend(pos, loc);

          // **إضافة جديدة:** حفظ سلوك السائق في قاعدة البيانات المحلية
          await _saveBehaviorIfMoved(pos, now, currentSpeed: speed);
        } catch (e) {
          print('Error in onLocationChanged: $e');
        }
      },
      onError: (e) => print('Location stream error: $e'),
    );
    print('📡 Subscribed to location stream.');
  }

  void _startTimers() {
    _trackInsertTimer?.cancel();
    _heartbeatTimer?.cancel();

    final trackDuration =
        _isPowerSavingMode ? trackInsertEveryPowerSave : trackInsertEveryNormal;
    final heartbeatDuration =
        _isPowerSavingMode ? heartbeatEveryPowerSave : heartbeatEveryNormal;

    _trackInsertTimer =
        Timer.periodic(trackDuration, (_) => _addSingleTrackPoint());
    _heartbeatTimer =
        Timer.periodic(heartbeatDuration, (_) => _sendStationaryHeartbeat());

    print('⏱️ Background timers started (Power Save: $_isPowerSavingMode).');
  }

  Future<void> _smartSend(LatLng pos, LocationData loc) async {
    final String driverStatus = box.read(BoxName.statusDriverLocation) ?? 'off';
    final distSinceSent =
        (_lastSentLoc == null) ? 999.0 : _haversineMeters(_lastSentLoc!, pos);

    final onMoveThreshold =
        _isPowerSavingMode ? onMoveMetersPowerSave : onMoveMetersNormal;
    final offMoveThreshold =
        _isPowerSavingMode ? offMoveMetersPowerSave : offMoveMetersNormal;

    bool shouldSend = false;

    if (driverStatus != _lastSentStatus) {
      shouldSend = true;
      if (driverStatus == 'on') {
        totalDistance = 0.0;
        _lastPosForDistance = pos;
      }
      print(
          'Status changed: ${_lastSentStatus ?? '-'} -> $driverStatus. Sending...');
    } else if (driverStatus == 'on') {
      if (distSinceSent >= onMoveThreshold) {
        shouldSend = true;
      }
    } else {
      // driverStatus == 'off'
      if (distSinceSent >= offMoveThreshold) {
        shouldSend = true;
      }
    }

    if (!shouldSend) return;

    await _sendUpdate(pos, driverStatus, loc);
  }

  // ===================================================================
  // ====== Battery Logic (منطق البطارية) ======
  // ===================================================================

  void _listenToBatteryChanges() async {
    _checkBatteryLevel(await _battery.batteryLevel);
    _batterySub =
        _battery.onBatteryStateChanged.listen((BatteryState state) async {
      _checkBatteryLevel(await _battery.batteryLevel);
    });
  }

  void _checkBatteryLevel(int level) {
    final bool wasInPowerSaveMode = _isPowerSavingMode;

    if (level <= powerSaveTriggerLevel) {
      _isPowerSavingMode = true;
    } else if (level >= powerSaveExitLevel) {
      _isPowerSavingMode = false;
    }

    if (_isPowerSavingMode != wasInPowerSaveMode) {
      if (_isPowerSavingMode) {
        Get.snackbar(
          "وضع توفير الطاقة مُفعّل",
          "البطارية منخفضة. سنقلل تحديثات الموقع للحفاظ على طاقتك.",
          snackPosition: SnackPosition.TOP,
          backgroundColor: Get.theme.primaryColor.withOpacity(0.9),
          colorText: Get.theme.colorScheme.onPrimary,
          duration: const Duration(seconds: 7),
        );
      } else {
        Get.snackbar(
          "العودة للوضع الطبيعي",
          "تم شحن البطارية. عادت تحديثات الموقع لوضعها الطبيعي.",
          snackPosition: SnackPosition.TOP,
          backgroundColor: Get.theme.colorScheme.secondary.withOpacity(0.9),
          colorText: Get.theme.colorScheme.onSecondary,
          duration: const Duration(seconds: 5),
        );
      }
      _startTimers();
    }
  }

  // ===================================================================
  // ====== API Communication & Helpers (التواصل مع السيرفر والدوال المساعدة) ======
  // ===================================================================

  Future<void> _sendUpdate(LatLng pos, String status, LocationData loc) async {
    final payload = _buildPayload(pos, status, loc);
    try {
      await CRUD().post(
        link: '${AppLink.locationServer}/update.php',
        payload: payload,
      );
      _lastSentLoc = pos;
      _lastSentStatus = status;
      _lastSentAt = DateTime.now();
      print('✅ Sent to update.php [$status]');
    } catch (e) {
      print('❌ FAILED to send to update.php: $e');
    }
  }

  Future<void> _addSingleTrackPoint() async {
    if (!_isReady) return;

    final String driverStatus =
        (box.read(BoxName.statusDriverLocation) ?? 'off').toString();

    if (myLocation.latitude == 0 && myLocation.longitude == 0) return;
    if (_lastSentLoc == null) return; // حماية إضافية

    // قيَم رقمية آمنة
    final double safeHeading =
        (heading is num) ? (heading as num).toDouble() : 0.0;
    final double safeSpeed = (speed is num) ? (speed as num).toDouble() : 0.0;
    final double safeDistKm = (totalDistance is num)
        ? (totalDistance as num).toDouble() / 1000.0
        : 0.0;

    final String driverId =
        (box.read(BoxName.driverID) ?? '').toString().trim();
    if (driverId.isEmpty) return; // لا ترسل بدون DriverID
    final String deviceTimestamp = DateTime.now().toIso8601String();

    // ✅ كل شيء Strings فقط
    final Map<String, String> payload = {
      'driver_id': driverId,
      'latitude': _lastSentLoc!.latitude.toStringAsFixed(6),
      'longitude': _lastSentLoc!.longitude.toStringAsFixed(6),
      'heading': safeHeading.toStringAsFixed(1),
      'speed': (safeSpeed < 0.5 ? 0.0 : safeSpeed)
          .toString(), // أو toStringAsFixed(2)
      'distance': safeDistKm.toStringAsFixed(2),
      'status': driverStatus,
      'carType': (box.read(BoxName.carType) ?? 'default').toString(),
      'device_timestamp': deviceTimestamp,
    };

    try {
      print('⏱️ Adding a single point to car_track... $payload');
      await CRUD().post(
        link: '${AppLink.locationServer}/add.php',
        payload: payload, // ← الآن Map<String,String>
      );
    } catch (e) {
      print('❌ FAILED to send single track point: $e');
    }
  }

  Future<void> _sendStationaryHeartbeat() async {
    if (!_isReady) return;
    if (_lastSentLoc == null || _lastSentAt == null) return;
    if (DateTime.now().difference(_lastSentAt!).inSeconds < 90) return;
    final distSinceSent = _haversineMeters(_lastSentLoc!, myLocation);
    if (distSinceSent >= onMoveMetersNormal) return;
    print('🫀 Driver is stationary, sending heartbeat...');

    final String driverStatus =
        (box.read(BoxName.statusDriverLocation) ?? 'off').toString();

    // ✅ كل شيء Strings
    final Map<String, String> payload = {
      'driver_id': (box.read(BoxName.driverID) ?? '').toString(),
      'latitude': _lastSentLoc!.latitude.toStringAsFixed(6),
      'longitude': _lastSentLoc!.longitude.toStringAsFixed(6),
      'heading': heading.toStringAsFixed(1),
      // ملاحظة: هنا السرعة تبقى بالمتر/ث بعد التحويل أدناه؛ وحّدتّها لكتابة String
      'speed': ((speed < 0.5) ? 0.0 : speed).toString(),
      'distance': (totalDistance / 1000).toStringAsFixed(2),
      'status': driverStatus,
      'carType': (box.read(BoxName.carType) ?? 'default').toString(),
      // 'hb': '1'
    };

    try {
      await CRUD().post(
        link: '${AppLink.locationServer}/update.php',
        payload: payload,
      );
      _lastSentAt = DateTime.now();
    } catch (e) {
      print('❌ FAILED to send Heartbeat: $e');
    }
  }

  Map<String, String> _buildPayload(
      LatLng pos, String status, LocationData loc) {
    return {
      'driver_id': (box.read(BoxName.driverID) ?? '').toString(),
      'latitude': pos.latitude.toStringAsFixed(6),
      'longitude': pos.longitude.toStringAsFixed(6),
      'heading': (loc.heading ?? heading).toStringAsFixed(1),
      // هنا أنت بتحوّل السرعة إلى كم/س (×3.6) — ممتاز
      'speed': ((loc.speed ?? speed) * 3.6).toStringAsFixed(1),
      'status': status,
      'distance': (totalDistance / 1000).toStringAsFixed(2),
      'carType': (box.read(BoxName.carType) ?? 'default').toString(), // 👈
    };
  }

  double _haversineMeters(LatLng a, LatLng b) {
    const p = 0.017453292519943295;
    final h = 0.5 -
        cos((b.latitude - a.latitude) * p) / 2 +
        cos(a.latitude * p) *
            cos(b.latitude * p) *
            (1 - cos((b.longitude - a.longitude) * p)) /
            2;
    return 12742 * 1000 * asin(sqrt(h));
  }

  // **إضافة جديدة:** دوال لحفظ سلوك السائق محلياً

  /// يحسب التسارع بالمتر/ثانية^2
  double? _calcAcceleration(double currentSpeed, DateTime now) {
    if (_lastSpeed != null && _lastSpeedAt != null) {
      final dt = now.difference(_lastSpeedAt!).inMilliseconds / 1000.0;
      if (dt > 0.5) {
        // لتجنب القيم الشاذة في الفترات الزمنية الصغيرة جداً
        final a = (currentSpeed - _lastSpeed!) / dt;
        _lastSpeed = currentSpeed;
        _lastSpeedAt = now;
        return a;
      }
    }
    _lastSpeed = currentSpeed;
    _lastSpeedAt = now;
    return null;
  }

  /// يحفظ سلوك السائق (الموقع، التسارع) في قاعدة بيانات SQLite المحلية
  Future<void> _saveBehaviorIfMoved(LatLng pos, DateTime now,
      {required double currentSpeed}) async {
    final dist =
        (_lastSqlLoc == null) ? 999.0 : _haversineMeters(_lastSqlLoc!, pos);
    if (dist < 15.0) return; // الحفظ فقط عند التحرك لمسافة 15 متر على الأقل

    final accel = _calcAcceleration(currentSpeed, now) ?? 0.0;
    try {
      final now = DateTime.now();

      final double lat =
          double.parse(pos.latitude.toStringAsFixed(6)); // دقة 6 أرقام
      final double lon =
          double.parse(pos.longitude.toStringAsFixed(6)); // دقة 6 أرقام
      final double acc = double.parse(
          (accel is num ? accel as num : 0).toStringAsFixed(2)); // دقة منزلتين

      await sql.insertData({
        'driver_id': (box.read(BoxName.driverID) ?? '').toString(), // TEXT
        'latitude': lat, // REAL
        'longitude': lon, // REAL
        'acceleration': acc, // REAL
        'created_at': now.toIso8601String(), // TEXT
        'updated_at': now.toIso8601String(), // TEXT
      }, TableName.behavior);
      _lastSqlLoc = pos;
    } catch (e) {
      print('❌ FAILED to insert to SQLite (behavior): $e');
    }
  }
}
